<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2018/6/11
 * Time: 23:18
 */

namespace app\common\lib\astrolog;

use app\common\lib\exception\ApiException;
use app\common\lib\Util;
use app\common\model\SyzygyTIme;
use Exception;
use think\Db;
use think\Log;

/**
 * 星盘数据类
 * Class Astrolog
 * @package app\common\lib\astrolog
 */
class Astrolog
{
    public static $_instance;
    /**
     * @var array
     * planets_display 默认显示的行星
     * planets_orb 默认的行星容许度
     * asps_display 默认显示的相位
     * asps_orb 默认的相位容许度
     * h_sys 默认分宫制 p 普莱西度
     * setting 星盘的相关配置（当前方案的所有配置）
     * recode1 档案资料1
     *      同数据库存储的档案信息
     * recode2 档案资料2
     *      同数据库存储的档案信息
     * advance 推进时间 + 经纬度（天象盘时）
     *      year
     *      month
     *      day
     *      hour
     *      minute
     *      timezone
     *      is_summer
     *      longitude
     *      latitude
     * day_chart 是否为日间盘
     * bound_type 界主默认使用default埃及界   || ptolemy_world托勒密界
     * decanates 十度配置 默认使用 欧洲古典0   || 印度古典1
     * profection_push_direction 小限月推运顺序 默认使用 逆时针0   || 顺时针1
     * push_fortune 推运基点 默认上升点
     * arabics 希腊点 默认不加载
     * location_use 返照盘使用地点 默认为现居地 0 || 出生地 1
     * mid_type 行星中点配置 默认为近中点 0 || 远中点 1 || 不考虑 2
     * use_default_setting 是否使用默认配置 【此时，setting 不能为空】
     * get_datas 需要获取的星盘数据【由chart组成的数组】
     * returnTime [日返|月返] 返照时间
     */
    public $options = [
        'planets_display' => '',
        'planets_orb' => [],
        'asps_display' => [],
        'asps_orb' => [],
        'h_sys' => 'p',
        'firdaria' => 'default',
        'setting' => [],
        'day_chart' => false,
        'bound_type' => 'default',
        'decanates' => 0,
        'profection_push_direction' => 0,
        'push_fortune' => 'p17',
        'arabics' => [],
        'location_use' => 0,
        'mid_type' => 0,
        'version' => 1,
    ];

    /**
     * exec_prefix exec 通用前缀字符
     * @var string
     */
    private $exec_prefix = '/astrolog/astrolog -edir/astrolog/ ';

    /**
     * 错误信息
     * @var string
     */
    protected $error = '';

    /**
     * 用户档案1
     * @var array
     */
    protected $recode1 = [];

    /**
     * 用户档案2
     * @var array
     */
    protected $recode2 = [];

    /**
     * 星盘推进信息
     * @var array
     */
    protected $advance = [];

    /**
     * 需要获取的星盘数据
     * @var array
     */
    protected $getDatas = [];

    /**
     * 是否为画盘数据
     * @var bool
     */
    protected $isAstrolabe = false;

    /**
     * 配置文件中的配置
     * @var string|null
     */
    protected $fileConfig = null;

    /**
     * 是否使用默认配置
     * @var bool
     */
    protected $useDefaultSetting = false;

    /**
     * chart 与获取对应星盘数据方法关系
     * @var array
     */
    protected static $funcRelations = [
        'now' => 'getNowData',// 天象盘
        'natal' => 'getNatalData',// 本命盘
        'transits' => 'getTransitsData',// 行运盘
        'thirdprogressed' => 'getThirdprogressedData',// 三限盘
        'thirdprogressedvsnatal' => 'getThirdprogressedVsNatalData',// 三限双盘
        'progressions' => 'getThirdprogressedData',// 次限盘
        'progressionsvsnatal' => 'getThirdprogressedVsNatalData',// 次限双盘
        'solar' => 'getSolarData',// 太阳弧盘
        'firdaria' => 'getFirdariaData',// 法达盘
        'profection' => 'getProfectionData',// 小限盘
        'synastry' => 'getSynastryData',// 比较盘
        'composite' => 'getCompositeData',// 组合中点盘
        'composite_thirdprogressed' => 'getCompositeThirdprogressedData',// 组合三限盘
        'composite_progressions' => 'getCompositeThirdprogressedData',// 组合次限盘
        'davison' => 'getDavisonData',// 时空中点盘
        'solar_return' => 'getSolarReturnData',// 太阳返照盘
        'solar_returnvsnatal' => 'getSolarReturnVsNatalData',// 太阳返照双盘
        'lunar_return' => 'getLunarReturnData',// 月亮返照盘
        'lunar_returnvsnatal' => 'getLunarReturnVsNatalData',// 月亮返照双盘
        'marks' => 'getMarksData',// 马克思盘
        'marks_thirdprogressed' => 'getMarksThirdprogressedData',// 马克思三限盘
        'marks_progressions' => 'getMarksThirdprogressedData',// 马克思次限盘
        'divination' => 'getDivinationData',// 卜卦盘
        'synastry_thirdprogressed' => 'getSynastryThirdprogressedData',// 比较三限盘
        'synastry_progressions' => 'getSynastryThirdprogressedData',// 比较次限盘
        'davison_thirdprogressed' => 'getDavisonThirdprogressedData',// 时空三限盘
        'davison_progressions' => 'getDavisonThirdprogressedData',// 时空次限盘
        #2019-07-24新增盘
        'fortune' => 'getFortuneData',// 福点盘
        'dodekatemorion' => 'getDodekatemorionData',// 十二分盘
        'trimsamsa' => 'getDodekatemorionData',// 十三分盘
        #20190830
        'zodrel' => 'getZodrelData',// 黄道星释盘
    ];

    protected $nowData = [];
    protected $natalData = [];
    protected $transitsData = [];
    protected $thirdprogressedData = [];
    protected $thirdprogressedvsnatalData = [];
    protected $progressionsData = [];
    protected $progressionsvsnatalData = [];
    protected $solarData = [];
    protected $firdariaData = [];
    protected $profectionData = [];
    protected $synastryData = [];
    protected $synastry_thirdprogressedData = [];
    protected $synastry_progressionsData = [];
    protected $compositeData = [];
    protected $composite_thirdprogressedData = [];
    protected $composite_progressionsData = [];
    protected $davisonData = [];
    protected $davison_thirdprogressedData = [];
    protected $davison_progressionsData = [];
    protected $solar_returnData = [];
    protected $solar_returnvsnatalData = [];
    protected $lunar_returnData = [];
    protected $lunar_returnvsnatalData = [];
    protected $marksData = [];
    protected $marks_thirdprogressedData = [];
    protected $marks_progressionsData = [];
    protected $fortuneData = [];
    protected $dodekatemorionData = [];
    protected $trimsamsaData = [];
    protected $zodrelData = [];

    /**
     * Astrolog constructor.
     */
    private function __construct()
    {
    }

    /**
     * 获取静态实例对象
     * @return Astrolog
     */
    public static function getInstance(): Astrolog
    {
        if (!(self::$_instance instanceof self))
        {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * 设置用户档案1信息
     * @param array $param
     * @return $this
     */
    public function setRecode1($param = []): self
    {
        $this->initInfo($param);
        $this->recode1 = $param;
        return $this;
    }

    /**
     * 设置用户档案2信息
     * @param array $param
     * @return $this
     */
    public function setRecode2($param = []): self
    {
        $this->initInfo($param);
        $this->recode2 = $param;
        return $this;
    }

    /**
     * 设置星盘推进信息
     * @param array $param
     * @return $this
     */
    public function setAdvance($param = []): self
    {
        $this->initInfo($param, 1);
        $this->advance = $param;
        return $this;
    }

    /**
     * 设置是否获取画盘数据
     * @param bool $param
     * @return $this
     */
    public function setIsAstrolabe($param = false): self
    {
        $this->isAstrolabe = $param;
        return $this;
    }

    /**
     * 设置获取星历数据时的前缀命令
     * @param string $param
     * @return $this
     */
    public function setExecPrefix($param = ''): self
    {
        $this->exec_prefix = $param;
        return $this;
    }

    /**
     * 设置要获取的星盘数据
     * @param array $param
     * @return $this
     */
    public function setGetDatas($param = []): self
    {
        $this->getDatas = $param;
        return $this;
    }

    /**
     * 设置计算星盘数据时的星盘配置
     * @param array $param
     * @return $this
     */
    public function setUserSetting($param = []): self
    {
        $this->options['setting'] = array_merge($this->options['setting'], $param);
        return $this;
    }

    /**
     * 设置当前逻辑版本号
     * 1 => 低于1.9.0版本使用的数据格式
     * 2 => 1.9.0版本使用的数据格式
     * @param int $ver
     * @return $this
     */
    public function setVersion($ver = 1): self
    {
        $this->options['version'] = (int)$ver;
        return $this;
    }

    /**
     * 返回错误信息
     * @return string
     */
    public function getError(): string
    {
        return $this->error;
    }

    /**
     * 获取某个盘的数据
     * @param string $param
     * @return mixed
     */
    public function getDatas($param = '')
    {
        return $this->{$param . 'Data'};
    }

    /**
     * 获取占星数据
     */
    public function getAstroDatas(): Astrolog
    {
        if (!empty($this->getDatas))
        {
            foreach ($this->getDatas as $chart)
            {
                // 切换对应的星盘配置
                $this->switchConfiguration($chart);

                // 调用对应的获取星盘数据的方法
                if (strpos($chart, 'progressions') !== false)
                {
                    $this->{$chart . 'Data'} = $this->{self::$funcRelations[$chart]}(365.2422);
                } elseif (strpos($chart, 'trimsamsa') !== false)
                {
                    $this->{$chart . 'Data'} = $this->{self::$funcRelations[$chart]}(1);
                } else
                {
                    $this->{$chart . 'Data'} = $this->{self::$funcRelations[$chart]}();
                }
            }
        }
        return $this;
    }

    /**
     * 获取档案1数据
     * @return array
     */
    public function getRecode1(): array
    {
        return $this->recode1;
    }

    /**
     * 获取档案2数据
     * @return array
     */
    public function getRecode2(): array
    {
        return $this->recode2;
    }

    /**
     * 获取推进数据
     * @return array
     */
    public function getAdvance(): array
    {
        return $this->advance;
    }

    /**
     * 获取配置文件中的星盘配置
     * @param string $name
     * @return mixed|string
     */
    private function getConfigFromFile($name = '')
    {
        if ($this->fileConfig === null)
        {
            $this->fileConfig = config('astrolog');
        }
        if ($name !== '')
        {
            return $this->fileConfig[$name];
        }
        return $this->fileConfig;
    }

    /**
     * 检查档案时间格式
     * @param int $year 年
     * @param int $month 月
     * @param int $day 日
     * @param int $hour 时
     * @param int $minute 分钟
     * @param number $timezone 时区
     * @return bool
     */
    public function checkRecodeData($year = null, $month = null, $day = null, $hour = null, $minute = null, $timezone = null): bool
    {
        // 年份限制 1900 - 2099
        if ($year === null || $year < 1000 || $year > 2999)
        {
            return false;
        }
        // 月份限制 1-12
        if ($month === null || $month < 0 || $month > 12)
        {
            return false;
        }
        $is_bissextile = $this->isBissextile($year);// 是否为闰年
        // 日期限制 1-31
        if ($day === null || $day < 0 || $day > 31
            || ($is_bissextile && $month === 2 && $day > 29)
            || (!$is_bissextile && $month === 2 && $day > 28)
            || (in_array($month, [4, 6, 9, 11], true) && $day > 30))
        {
            return false;
        }
        // 小时限制 0-23
        if ($hour === null || $hour < 0 || $hour > 23)
        {
            return false;
        }
        // 分钟限制 0-59
        if ($minute === null || $minute < 0 || $minute > 59)
        {
            return false;
        }
        if ($timezone < -12 || $timezone > 12)
        {
            return false;
        }
        return true;
    }

    /**
     * 判断是否为闰年
     * 闰年 true || 平年 false
     * @param null $year
     * @return bool
     */
    public function isBissextile($year = null): bool
    {
        if ($year === null)
        {
            return false;
        }
        if ($year % 400 === 0 || ($year % 100 !== 0 && $year % 4 === 0))
        {
            return true;
        }
        return false;
    }

    /**
     * 初始化时间经纬度信息
     * @param $info
     * @param int $isAdvance
     */
    private function initInfo(&$info, $isAdvance = 0): void
    {
        if (isset($info['timezone']) && $info['timezone'] > 12)
        {//咨询师端h5星盘，咨询师在新西兰，h5传入时区为13，临时处理
            $info['is_summer'] = 1;
            $info['timezone'] = 12;
        }
        $info['ut_timestamp'] = $this->dealTime($info);
        [$info['ut_date'], $info['ut_time'], $info['ut_year'], $info['ut_month'], $info['ut_day'], $info['ut_hour'], $info['ut_minute'], $info['ut_second']] = explode(',', strftime('%d.%m.%Y,%H:%M:%S,%Y,%m,%d,%H,%M,%S', $info['ut_timestamp']));
        $info['ut_jd'] = gregoriantojd($info['ut_month'], $info['ut_day'], $info['ut_year']) + (($info['ut_hour'] + ($info['ut_minute'] / 60)) / 24);//  - 0.5

        if (!$isAdvance)
        {
            if (!isset($info['birth_lng']))
            {
                $info['birth_lng'] = $info['longitude'] ?? ($info['long_deg'] + $info['long_min'] / 60) * $info['ew'];
            }

            if (!isset($info['brith_lat']))
            {
                $info['birth_lat'] = $info['latitude'] ?? ($info['lat_deg'] + $info['lat_min'] / 60) * $info['ns'];
            }
        } else
        {
            try
            {
                if (!isset($info['longitude']))
                {
                    $info['longitude'] = ($this->recode1['long_deg'] + $this->recode1['long_min'] / 60) * $this->recode1['ew'];
                }

                if (!isset($info['latitude']))
                {
                    $info['latitude'] = ($this->recode1['lat_deg'] + $this->recode1['lat_min'] / 60) * $this->recode1['ns'];
                }
            }
            catch (Exception $e)
            {
//                Log::write('advance=' . var_export($info, true), 'error', true);
                // 若经纬度未设置，则默认使用北京市朝阳区政府经纬度
                $info['longitude'] = 116.443153;
                $info['latitude'] = 39.921466;
            }

        }
    }

    /**
     * 时间信息处理
     * @param array $timeinfo
     * @return false|int
     */
    public function dealTime($timeinfo = [])
    {
        $year = (int)$timeinfo['year'];
        $month = (int)$timeinfo['month'];
        $day = (int)$timeinfo['day'];
        $hour = (int)$timeinfo['hour'];
        $minute = (int)$timeinfo['minute'];
        $second = 0;
        $is_summer = (int)$timeinfo['is_summer'];
        $timezone = $timeinfo['timezone'];

        $this->checkRecodeData($year, $month, $day, $hour, $minute, $timezone);

        // 夏令时
        if ($is_summer)
        {
            $hour--;
        }
        // 时区处理
        if ($timezone >= 0)
        {
            $whole = floor($timezone);
            $fraction = $timezone - floor($timezone);
        } else
        {
            $whole = ceil($timezone);
            $fraction = $timezone - ceil($timezone);
        }
        $hour -= $whole;
        $minute -= ($fraction * 60);
        return mktime($hour, $minute, $second, $month, $day, $year);
    }

    /**
     * 检测运势推进时间是否早于出生时间
     * @param null $time1 出生时间
     * @param null $time2 推进时间
     * @return bool true时间正常|false时间异常
     */
    protected function checkTime($time1 = null, $time2 = null): bool
    {
        if ($time2 < $time1)
        {
            $this->error = '当前选择时间早于出生时间';
            return false;
        }
        return true;
    }

    /**
     * 获取星盘原始数据
     * @param array $data
     * @return array|bool
     */
    protected function getOriginalData($data = [])
    {
        if (!is_countable($data) || count($data) < 20)
        {
            Log::write('行星数据获取失败，请检查', 'error', true);
            $this->error = '行星数据获取失败，请检查';
            return false;
        }
        $planet = [];
        $speed = [];
        foreach ($data as $key => $line)
        {
            $row = explode(',', $line);
            $planet[$key] = @(float)$row[0] * 1;
            $declination[$key] = isset($row[1]) ? (float)$row[1] * 1 : 0;
            $speed[$key] = $key > 14 ? 0 : (float)$row[2];
        };

//        $juno = $planet[13];// 婚神星
//        $vert = $planet[30];// 宿命点度数
        $speed[16] = $speed[12];

        [$juno, $vert, $asc, $mc] = [$planet[13], $planet[30], $planet[27], $planet[28]];
        $des = $asc >= 180 ? $asc - 180 : $asc + 180;
        $ic = $mc >= 180 ? $mc - 180 : $mc + 180;

        // 判断是日间盘还是夜间盘
        if ($asc > $des)
            if ($planet[0] <= $asc && $planet[0] > $des)
                $day_chart = true;
            else
                $day_chart = false;
        else
            if ($planet[0] > $asc && $planet[0] <= $des)
                $day_chart = false;
            else
                $day_chart = true;

        // 计算福点位置
        if ($day_chart === true) $fort = $asc + $planet[1] - $planet[0];
        else $fort = $asc - $planet[1] + $planet[0];
        if ($fort >= 360) $fort -= 360;
        if ($fort < 0) $fort += 360;
        $speed[14] = 1;//福点数据不存在逆行

        $hc = [];

        for ($i = 1; $i <= 14; $i++)
        {
            $hc[$i] = $planet[14 + $i];
            unset($planet[14 + $i]);
        }

        unset($hc[13], $hc[14], $planet[29], $planet[30]);

        $planet[13] = $juno;// 婚神星
        $planet[14] = $fort;// 福点
        $planet[15] = $vert;// 宿命点
        $planet[16] = $planet[12] > 180 ? $planet[12] - 180 : $planet[12] + 180;// 增加南交点
        // 加四轴 放入行星组中
        $planet[17] = $asc;// 上升点
        $planet[18] = $ic;// 天底
        $planet[19] = $des;// 下降点
        $planet[20] = $mc;// 天顶

        $returnData = ['p1' => $planet, 'hc1' => $hc, 'speed' => $speed, 'day_chart' => $day_chart];

        $this->options['day_chart'] = $day_chart;

        return $returnData;
    }

    /**
     * 隐藏不显示的行星
     * 十大行星强制返回数据
     * @param $arr
     */
    protected function arrayRemove(&$arr): void
    {
        $result = [];
        for ($i = 0; $i <= MC; $i++)
        {
            // 十大行星、上升、天顶、（福点盘 福点） 不允许删除
            if ((int)$this->options['planets_display'][$i] === 1 || $i < 10 || in_array($i, [17, 20], true) || ($i === 14 && isset($this->options['setting']['fortune'])))
            {
                $result['p1'][$i] = $arr['p1'][$i];
                $result['speed'][$i] = $arr['speed'][$i];
            }
        }
        $result['hc1'] = $arr['hc1'];

        $result['day_chart'] = $arr['day_chart'];

        $arr = $result;
    }

    /**
     * 行星落入星座度数
     * 如：18°2'26''
     * @param $deg
     * @return float [type] [description]
     */
    protected function inSignDegFloor($deg): float
    {

        $sign_id = floor($deg / 30);

        $pos_in_sign = $deg - ($sign_id * 30);

        return (float)$pos_in_sign;
    }

    /**
     * 入星座度数
     * 如：18°2'26''  || 18°3′
     * @param $deg
     * @param bool $get_sec
     * @return string
     */
    protected function inSignDeg($deg, $get_sec = false): string
    {
        $longitude = $deg;
        $sign_id = (int)floor($longitude / 30);
        $pos_in_sign = $longitude - ($sign_id * 30);
        $deg = (int)floor($pos_in_sign);
        $full_min = ($pos_in_sign - $deg) * 60;
        $min = (int)floor($full_min);
        $sec = (int)round(($full_min - $min) * 60);

        if (!$get_sec)
        {
            // 四舍五入
            if ($deg !== 29 && $min !== 59 && $sec >= 30)
            {
                $min++;
            }
            if ($min === 60)
            {
                $min = 0;
                $deg++;
            }
            $min = sprintf('%02u', $min);
            return $deg . '°' . $min . '′';
        }
        $min = sprintf('%02u', $min);
        $sec = sprintf('%02u', $sec);
        return $deg . '°' . $min . '′' . $sec . '″';
    }

    /**
     * 获取行星、宫头、详细信息
     * @param array $data 行星数据
     * @param array $house 宫位数据 用户计算行星落宫位
     * @param int $year 年份，用于计算恒星汇合
     * @param array $false 设置某些行星(在arrayRemove中不删除的那些)不进行绘制
     * @return array
     */
    protected function getPlanetHouseDetail($data, $house = [], $year = 0, $false = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 20]): array
    {
        $planetHouseDetails = [];

        for ($i = 0; $i <= MC; $i++)
        {
            // 不显示的行星不进行处理
            if (!isset($data['p1'][$i])) continue;

            $longitude = $data['p1'][$i];
            $in_sign = (int)ceil($longitude / 29.999999999999);// 行星在星座
            if ($in_sign < 1) $in_sign = 1;// 整宫制上升0°时 BUG修复
            elseif ($in_sign > 12) $in_sign = 12;// 360/12 ceil后为13
            $in_sign_deg = $this->inSignDeg($longitude);// 行星在星座的度数
            $in_sign_deg_e = $longitude - ($in_sign - 1) * 30;// 行星在星座的度数
            $in_house = $this->inWhichHouse($longitude, $house);// 行星落宫
            $speed = @$data['speed'][$i] ? $data['speed'][$i] : 0;// 行星速度

            $planetHouseDetails['planets'][$i]['id'] = $i;
            $planetHouseDetails['planets'][$i]['speed'] = $speed;
            $planetHouseDetails['planets'][$i]['deg'] = $this->degFormat($longitude);
            $planetHouseDetails['planets'][$i]['in_sign_id'] = $in_sign;
            $planetHouseDetails['planets'][$i]['in_sign_deg'] = $in_sign_deg;
            $planetHouseDetails['planets'][$i]['in_sign_deg_e'] = $this->degFormat($in_sign_deg_e);

            $planetHouseDetails['planets'][$i]['in_house_id'] = $in_house;
            // 若十大行星 或 上升天顶关闭，则is_draw=false 不进行绘制
            if ($this->options['planets_display'][$i] == 0 && in_array($i, $false))
            {
                $planetHouseDetails['planets'][$i]['is_draw'] = false;
            } else
            {
                $planetHouseDetails['planets'][$i]['is_draw'] = true;
            }

            $planetHouseDetails['planets'][$i]['ancient'] = $this->planetInAncient($i, $in_sign, $this->inSignDegFloor($longitude));
            $sun_in_out = $this->orientalOrOccidentalSun($i, $data['p1'][0], $longitude);// 东出西入
            $planetHouseDetails['planets'][$i]['ancient']['sun_in_out'] = $sun_in_out;
            $planetHouseDetails['planets'][$i]['ancient']['hagy'] = $this->planetHagy($i, $in_sign, $in_house, $sun_in_out, $data['day_chart']);
            $planetHouseDetails['planets'][$i]['ancient']['sun_dist'] = $this->planetSunDist($i, $data['p1'][0], $longitude);
            $planetHouseDetails['planets'][$i]['ancient']['like_house'] = $this->planetInLikeHouse($i, $in_house);
            $planetHouseDetails['planets'][$i]['ancient']['burn_way'] = $this->planetInBurnWay($i, $in_sign, $in_sign_deg_e);
            $planetHouseDetails['planets'][$i]['ancient']['antipode'] = $this->planetAntipode($i, $longitude, $data['p1']);
            $planetHouseDetails['planets'][$i]['ancient']['star'] = [];

            if ($year > 0)
            {
                if (!in_array($i, [0, 1, 2, 3, 4, 5, 6, ASC, IC, DES, MC], true)) continue;
                $diff = ($year * 1 - 2000) * 0.83 / 60;
                // 计算恒星 每一百年移动83′ 每年0.83分
                foreach ($this->getConfigFromFile('star') as $s)
                {
                    $star = $s[0] + $diff;
                    if ($star >= 360) $star -= 360;
                    $light = $s[4];// 亮度

                    $da = abs($longitude - $star);
                    // 亮度小于1.4，容许度2；亮度1.4-2.1，容许度1.5    20180211 edit by Seunk
                    if (
                        ($da <= 2 && $light < 1.4)
                        || ($da >= 358 && $da <= 360 && $light < 1.4)
                        || ($da <= 2 && $light >= 1.4 && $light < 2.1)
                        || ($da >= 358 && $da <= 360 && $light >= 1.4 && $light < 2.1)
                        || ($da <= 1 && $light >= 2.1)
                        || ($da >= 359 && $da <= 360 && $light >= 2.1)
                    )
                    {
                        $s_in_sign = ceil($star / 30);// 行星在星座
                        $s_in_sign_deg = $this->inSignDeg($star);// 行星在星座的度数  不显示秒
                        $s_s = [
                            'deg' => $this->degFormat($star),
                            'name' => $s[1],
                            'belong_sign' => $s[2],
                            'planet_attr' => $s[3],
                            'influences' => $s[4],
                            'description' => $s[5],
                            'auspicious' => $s[6],// 吉凶状态  凶 平 吉 大吉
                            'in_sign_deg' => $s_in_sign_deg,
                            'in_sign' => $s_in_sign,
                            'con_planet_id' => $i,
                        ];
                        $isMars = $i === 4;

                        if ($s[1] === '壁宿二' && $i === 0)
                        {
                            $s_s['auspicious'] = '凶';
                        } elseif ($s[1] === '天狼星' && $i === MC)
                        {
                            $s_s['auspicious'] = '大吉';
                        } elseif ($s[1] === '水委一' && $i === 5)
                        {
                            $s_s['auspicious'] = '大吉';
                        } elseif ($s[1] === '北落师门' && ($i === 2 || $i === 3))
                        {
                            $s_s['auspicious'] = '吉';
                        } elseif ($s[1] === '参宿七' && ($i === 0 || $i === 1 || $i === ASC || $i === MC))
                        {
                            $s_s['auspicious'] = '大吉';
                        } elseif ($s[1] === '参宿四' && $isMars)
                        {
                            $s_s['auspicious'] = '凶';
                        } elseif ($s[1] === '太微左垣一' && ($isMars || $i === 6))
                        {
                            $s_s['auspicious'] = '平';
                        } elseif ($s[1] === '贯索四' && ($isMars || $i === 8))
                        {
                            $s_s['auspicious'] = '平';
                        } elseif ($s[1] === '马腹一')
                        {
                            if ($i === ASC || $i === 2)
                            {
                                $s_s['auspicious'] = '吉';
                            } elseif ($isMars || $i === 6 || $i === 8)
                            {
                                $s_s['auspicious'] = '凶';
                            } else
                            {
                                $s_s['auspicious'] = '平';
                            }
                        }

                        $planetHouseDetails['planets'][$i]['ancient']['star'][] = $s_s;
                        $planetHouseDetails['star'][] = $s_s;
                    }
                }
            } else
            {
                $planetHouseDetails['planets'][$i]['ancient']['star'] = null;
                $planetHouseDetails['star'] = null;
            }
        }

        //循环12宫
        for ($i = 1; $i <= 12; $i++)
        {
            $house_deg = @$house[$i] * 1;
            if ($house_deg > 360) $house_deg -= 360;

            $in_sign = (int)ceil($house_deg / 29.999999999999);
            if ($in_sign < 1) $in_sign = 1;// 整宫制上升0°时 BUG修复
            elseif ($in_sign > 12) $in_sign = 12;// 360/12 ceil后为13
            $in_sign_deg = $this->inSignDeg($house_deg);

            $planetHouseDetails['houses'][$i]['deg'] = $this->degFormat($house_deg);
            $planetHouseDetails['houses'][$i]['in_sign_id'] = $in_sign;
            $planetHouseDetails['houses'][$i]['in_sign_deg'] = $in_sign_deg;
            // 现占 // 宫主星信息
            $protect_id = $this->getConfigFromFile('protect_id')[$in_sign - 1];// 宫主星id
            $planetHouseDetails['houses'][$i]['protect_id'] = $protect_id;

            $planetHouseDetails['houses'][$i]['protect_insign_id'] = $planetHouseDetails['planets'][$protect_id]['in_sign_id'];
            $planetHouseDetails['houses'][$i]['protect_insign_deg'] = $planetHouseDetails['planets'][$protect_id]['in_sign_deg'];
            // 现占 // 宫主飞星信息
            $planetHouseDetails['houses'][$i]['protect_inhouse_id'] = $planetHouseDetails['planets'][$protect_id]['in_house_id'];

            // 古占 // 宫主星信息
            $protect_ancient_id = $this->getConfigFromFile('protect_ancient_id')[$in_sign - 1];// 宫主星id
            $planetHouseDetails['houses'][$i]['protect_ancient_id'] = $protect_ancient_id;
            $planetHouseDetails['houses'][$i]['protect_ancient_insign_id'] = $planetHouseDetails['planets'][$protect_ancient_id]['in_sign_id'];
            $planetHouseDetails['houses'][$i]['protect_ancient_insign_deg'] = $planetHouseDetails['planets'][$protect_ancient_id]['in_sign_deg'];
            // 古占 // 宫主飞星信息
            $planetHouseDetails['houses'][$i]['protect_ancient_inhouse_id'] = $planetHouseDetails['planets'][$protect_ancient_id]['in_house_id'];
            $planetHouseDetails['houses'][$i]['in_house_area_planet_info'] = [];// 落入当前宫位的行星信息
            $num = 0;
            foreach ($planetHouseDetails['planets'] as $k => $pls)
            {
                if ($this->options['planets_display'][$k] != 1) continue;
//                if ($k != 17 && $k != IC && $k != DES && $k != 20 && $pls['in_house_id'] == $i)
                if ($k < 10 && $pls['in_house_id'] == $i)
                {
                    $planetHouseDetails['houses'][$i]['in_house_area_planet_info'][] = [
                        'id' => $k,
                        'deg' => $planetHouseDetails['planets'][$k]['deg'],// 行星度数
                    ];
                    $num++;
                }
            }
            $planetHouseDetails['houses'][$i]['have_planet_num'] = $num;// 计算当前宫位有几个行星

            $planetHouseDetails['houses'][$i]['house_almuten'] = $this->houseAlmuten($in_sign, $this->inSignDegFloor($house_deg));//宫神星
        }
        $planetHouseDetails['arabics'] = $this->getTheArabics($planetHouseDetails['planets'], $planetHouseDetails['houses'], $data['day_chart']);

        return $planetHouseDetails;
    }

    /**
     * 获取行星间相位信息
     * @param array $data1
     * @param array $data2
     * @param bool $pkself
     * @param int $vs
     * @return array
     */
    protected function planetPkPlanet($data1 = [], $data2 = [], $pkself = false, $vs = 0): array
    {
        $planetPkPlanet = [];
        $planetPkPlanet['phase'] = [];
        $planet1 = $data1['p1'];
        $planet2 = $data2['p1'];
        $speed1 = $data1['speed'];
        $speed2 = $data2['speed'];
        // 相位计算
        for ($i = 0; $i <= 20; $i++)
        {
            if (!isset($planet1[$i])) continue;
            // 行星1 度数
            $longitude1 = $planet1[$i];
            $p_orb1 = $this->options['planets_orb'][$i] ?? 0;
            $planetPkPlanetPhase = [];
            for ($j = 0; $j <= 20; $j++)
            {
                if (!isset($planet2[$j])) continue;
                // 行星2 度数
                $longitude2 = $planet2[$j];
                $q = -1;
                // 避免重复
                if ($pkself == true && ($i == $j || ($i >= 17 && $j >= 17))) continue;
                $da = abs($longitude1 - $longitude2);
                if ($da > 180) $da = 360 - $da;

                $p_orb2 = $this->options['planets_orb'][$j] ?? 0;
                $p_orb = $p_orb1 + $p_orb2;
                $orb = null;
                // 判断相位
                foreach ($this->options['asps_display'] as $k => $asps)
                {
                    $asp_deg = $asps;

                    $asp_deg_orb = $this->options['asps_orb'][$asp_deg];

                    if (($da <= ($asp_deg + $asp_deg_orb + $p_orb)) && ($da >= ($asp_deg - $asp_deg_orb - $p_orb)))
                    {
                        $q = $asp_deg;
                        $orb = $asp_deg_orb + $p_orb;
                    }

                }
                if ($q >= 0)
                {
                    $phase_orb = abs($da - $q);
                    // 计算出入相位----------------------------------------------
                    if ($i >= ASC || $j >= ASC)
                    {
                        $in_or_out = -1;
                    } else
                    {
                        $in_or_out_status = $this->phaseInOrOut($q, $longitude1, $longitude2, $speed1[$i], $speed2[$j], $phase_orb, $vs);
                        if ($in_or_out_status) $in_or_out = 1;// 入相
                        else $in_or_out = 0;// 出相
                    }
                    $planetPkPlanetPhase[$i . '-' . $j]['phase_e'] = $q;
                    $planetPkPlanetPhase[$i . '-' . $j]['phase_or_orb'] = $orb;
                    $planetPkPlanetPhase[$i . '-' . $j]['phase_orb'] = $this->degFormat($phase_orb);
                    $planetPkPlanetPhase[$i . '-' . $j]['phase_change'] = $in_or_out;
                    $planetPkPlanetPhase[$i . '-' . $j]['id'] = $j;
                    // 判断相位方向  用于区分如同向90° 和  两个方向的90°
//                    if ($q == 0 || $q == 180)
//                    {
//                        $planetPkPlanetPhase[$i . '-' . $j]['phase_type'] = 0;// 相位方向
//                    } else
//                    {
                    if ($longitude1 < $longitude2 || ($longitude2 - $longitude1) > 180)
                    {
                        $planetPkPlanetPhase[$i . '-' . $j]['phase_type'] = 1;
                    } else
                    {
                        $planetPkPlanetPhase[$i . '-' . $j]['phase_type'] = 0;
                    }
//                    }
                    $planetPkPlanet['phase'][] = [
                        'id1' => $i,
                        'id2' => $j,
                        'phase_deg' => $q,
                        'orb' => $this->degFormat(abs($da - $q)),
                        'or_orb' => $orb,
                    ];
                }
            }
            $planetPkPlanet['planets'][$i]['phase'] = $planetPkPlanetPhase;
        }
        return $planetPkPlanet;
    }

    /**
     *  获取太阳弧数据
     * @param  [type] $p_sun [太阳度数]
     * @param array $data
     * @return array [type]        [太阳弧行星数据]
     */
    protected function getTheLongitudeBySolarArc($p_sun, $data = []): array
    {
        $p1 = $data['p1'];

        $solar_arc = Crunch($p_sun - $p1[0]);

        $longitude = [];

        foreach ($p1 as $i => $p)
        {
            $longitude[$i] = Crunch($p + $solar_arc);
        }

        $ret = ['p1' => $longitude, 'speed' => $data['speed'], 'day_chart' => $data['day_chart']];

        return $ret;
    }

    /**
     * 组合盘中点计算
     * @param array $data1 [description]
     * @param array $data2 [description]
     * @return array [type]        [description]
     */
    protected function getTheCompoisteCenter($data1 = array(), $data2 = array()): array
    {
        $rx1 = '';

        for ($i = 0; $i <= 12; $i++)
        {
            $rx1 .= ' ';
        }

        $longitude = $speed = $hc1x = $hc2x = $hc3x = $hc3 = [];

        foreach ($data1['p1'] as $i => $d)
        {
            $longitude[$i] = ($data1['p1'][$i] + $data2['p1'][$i]) / 2;
            $diff = abs($data1['p1'][$i] - $data2['p1'][$i]);

            if (
                $diff >= 180
                && abs($longitude[$i] - $data1['p1'][$i]) > 90
                && abs($longitude[$i] - $data2['p1'][$i]) > 90
            )
            {
                $longitude[$i] += 180;
            }

            $longitude[$i] = (float)sprintf('%.3f', Crunch($longitude[$i]));

            $speed[$i] = ($data1['speed'][$i] + $data2['speed'][$i]) / 2;
        }

        for ($i = 10; $i <= 12; $i++)
        {
            $hc1x[$i - 9] = $data1['hc1'][$i];
            $hc2x[$i - 9] = $data2['hc1'][$i];
        }

        for ($i = 1; $i <= 9; $i++)
        {
            $hc1x[$i + 3] = $data1['hc1'][$i];
            $hc2x[$i + 3] = $data2['hc1'][$i];
        }

        for ($i = 1; $i <= 12; $i++)
        {
            $hc3x[$i] = ($hc1x[$i] + $hc2x[$i]) / 2;
            // 不考虑 2
            if ($this->options['mid_type'] !== 2)
            {
                // 远中点 1
                if ($this->options['mid_type'] === 1)
                {
                    // 选用远中点
                    if (abs($hc3x[$i] - $hc1x[$i]) < 90 || abs($hc3x[$i] - $hc2x[$i]) < 90)
                    {
                        $hc3x[$i] += 180;
                    }
                }// 近中点 0
                else
                {
                    // 选用近中点
                    if (abs($hc3x[$i] - $hc1x[$i]) > 90 || abs($hc3x[$i] - $hc2x[$i]) > 90)
                    {
                        $hc3x[$i] += 180;
                    }
                }
            }

            if ($hc3x[$i] >= 360)
            {
                $hc3x[$i] -= 360;
            }

            if ($i >= 2)
            {
                $hc3xIDiffPreAbs = abs($hc3x[$i] - $hc3x[$i - 1]);
                if ($hc3xIDiffPreAbs > 90 && $hc3xIDiffPreAbs < 270)
                {
                    $hc3x[$i] = Crunch($hc3x[$i] + 180);
                }
            }
        }

        for ($i = 1; $i <= 9; $i++)
        {
            $hc3[$i] = sprintf('%.3f', $hc3x[$i + 3]);
        }

        for ($i = 10; $i <= 12; $i++)
        {
            $hc3[$i] = sprintf('%.3f', $hc3x[$i - 9]);
        }

        $longitude[ASC] = $hc3[1];
        $longitude[IC] = $hc3[4];
        $longitude[DES] = $hc3[7];
        $longitude[MC] = $hc3[10];

        // 判断是日间盘还是夜间盘
        if ($longitude[ASC] > $longitude[DES])
        {
            if ($longitude[0] <= $longitude[ASC] && $longitude[0] > $longitude[DES])
            {
                $day_chart = true;
            } else
            {
                $day_chart = false;
            }
        } else
        {
            if ($longitude[0] > $longitude[ASC] && $longitude[0] <= $longitude[DES])
            {
                $day_chart = false;
            } else
            {
                $day_chart = true;
            }
        }

        $ret = ['rx1' => $rx1, 'p1' => $longitude, 'hc1' => $hc3, 'speed' => $speed, 'day_chart' => $day_chart];

        return $ret;
    }

    /**
     * 三限盘数据计算
     * @param array $before 上整月
     * @param array $after 下整月
     * @param int $changePro 变化比率
     * @return array
     */
    protected function getProgressionThirdprogressed($before = array(), $after = array(), $changePro = 0): array
    {
        $temp = [];
        foreach ($before as $k => $v)
        {
            $t1 = explode(',', $before[$k]);
            $t2 = explode(',', $after[$k]);
            $p1 = $t1[0] * 1;
            $p2 = $t2[0] * 1;

            $isCrossPis = abs($p1 - $p2) > 180;
            /**
             * 当p1为逆行时
             */
            if ($t1[2] * 1 < 0)
            {
                /**
                 * 从白羊座跨度到双鱼座
                 */
                if ($isCrossPis)
                {
                    $p = $p1 - ($p1 + 360 - $p2) * $changePro;
                } else
                {
                    $p = $p1 - ($p1 - $p2) * $changePro;
                }
            } elseif ($isCrossPis)
            {
                $p = $p1 + ($p2 + 360 - $p1) * $changePro;
            } else
            {
                $p = $p1 + ($p2 - $p1) * $changePro;
            }
            $p = $this->mod360($p);
            // TODO d/s   计算真实平均值
            $r1 = isset($t1[2]) ? $t1[2] * 1 : 0;
//            $r2 = isset($t2[2]) ? $t2[2] * 1 : 0;
//            $r = $r1 + ($r2 - $r1) * $changePro;

            $temp[] = $p . ',' . $t1[1] . ',' . $r1;
        }

        return $temp;
    }

    /**
     * 计算行星  1入庙 或 2失势
     * @param int $p_id 行星ID
     * @param int $p_insign_id 行星落座id
     * @param float $p_insign_deg 行星落座度数
     * @return array
     */
    protected function planetInAncient($p_id = null, $p_insign_id = null, $p_insign_deg = 0.0)
    {
        // 非古典七星落座位置也有该位置庙旺弱陷界十度信息
        if ($p_id === null || $p_id < 0 || $p_insign_id === null) return null;
        $ret = [
            'plus' => 0,// 加分项，用来判断接纳互容
            'power' => 0,
            'walls' => -1, 'walls_cn' => '',// 庙
            'promote' => -1, 'promote_cn' => '',// 旺
            'trisection' => -1, 'trisection_cn' => '',// 三分
            'extent' => -1, 'extent_cn' => '',// 界
            'period' => -1, 'period_cn' => '',// 面
            'migration' => -1, 'migration_cn' => '',// 游走
            'or_walls_planet_id' => -1, 'or_promote_planet_id' => -1,
            'or_extent_planet_id' => -1, 'or_period_planet_id' => -1,
            'or_trisection_planet_id' => [],
        ];

        $fall = ($p_insign_id <= 6) ? ($p_insign_id + 6) : ($p_insign_id - 6);


        $config_ancient = $this->getConfigFromFile('ancient')[$p_insign_id];
        $config_ancient_fall = $this->getConfigFromFile('ancient')[$fall];

        if ($p_id < 7)
        {
            // 入庙
            if ($config_ancient[0] === $p_id)
            {
                $ret['plus'] += 5;
                $ret['power'] += 5;
                $ret['walls'] = 1;
                $ret['walls_cn'] = '入庙';
            } elseif ($config_ancient_fall[0] === $p_id)
            {
                $ret['power'] -= 5;
                $ret['walls'] = 2;
                $ret['walls_cn'] = '失势';
            }
        }
        // 入庙
//        if ($p_id < 7 && $config_ancient[0] == $p_id)
//        {
//            $ret['plus'] += 5;
//            $ret['power'] += 5;
//            $ret['walls'] = 1;
//            $ret['walls_cn'] = '入庙';
//        } elseif ($p_id < 7 && $config_ancient_fall[0] == $p_id)
//        {
//            $ret['power'] -= 5;
//            $ret['walls'] = 2;
//            $ret['walls_cn'] = '失势';
//        }

        $ret['or_walls_planet_id'] = $config_ancient[0];
        $ret['or_walls_fall_planet_id'] = $config_ancient_fall[0];
        // 天王星  入庙 失势
        if ($p_id === 7)
        {
            if ($p_insign_id == 11)
            {
                $ret['plus'] += 5;
                $ret['power'] += 5;
                $ret['walls'] = 1;
                $ret['walls_cn'] = '入庙';
            } elseif ($p_insign_id == 5)
            {
                $ret['power'] -= 5;
                $ret['walls'] = 2;
                $ret['walls_cn'] = '失势';
            }
        }
        // 海王星  入庙 失势
        if ($p_id === 8)
        {
            if ($p_insign_id == 12)
            {
                $ret['plus'] += 5;
                $ret['power'] += 5;
                $ret['walls'] = 1;
                $ret['walls_cn'] = '入庙';
            } elseif ($p_insign_id == 6)
            {
                $ret['power'] -= 5;
                $ret['walls'] = 2;
                $ret['walls_cn'] = '失势';
            }
        }
        // 冥王星  入庙 失势
        if ($p_id === 9)
        {
            if ($p_insign_id == 8)
            {
                $ret['plus'] += 5;
                $ret['power'] += 5;
                $ret['walls'] = 1;
                $ret['walls_cn'] = '入庙';
            } elseif ($p_insign_id == 2)
            {
                $ret['power'] -= 5;
                $ret['walls'] = 2;
                $ret['walls_cn'] = '失势';
            }
        }
        // 擢升
        if ($config_ancient[1] !== '' && $config_ancient[1] === $p_id)
        {
            $ret['plus'] += 4;
            $ret['power'] += 4;
            $ret['promote'] = 1;
            $ret['promote_cn'] = '擢升';
        } elseif ($config_ancient_fall[1] !== '' && $config_ancient_fall[1] === $p_id)
        {
            $ret['power'] -= 4;
            $ret['promote'] = 2;
            $ret['promote_cn'] = '落陷';
        }
        // 当擢升没有时  保持原始值-1【int】
        $ret['or_promote_planet_id'] = $config_ancient[1] !== '' ? $config_ancient[1] : -1;
        $ret['or_promote_fall_planet_id'] = $config_ancient_fall[1] !== '' ? $config_ancient_fall[1] : -1;
        // 三分
        if (in_array($p_id, $config_ancient[2], true))
        {
            $ret['plus'] += 3;
            $ret['power'] += 3;
            $ret['trisection'] = 1;
            $ret['trisection_cn'] = '三分';
        }
        $ret['or_trisection_planet_id'] = $config_ancient[2];
        // 界主 界主为1 +2
        // 使用埃及界
        $extent = $config_ancient[3][$this->options['bound_type']];

        for ($i = 0; $i < 5; $i++)
        {
            if ($p_insign_deg > $extent[1][$i] && $p_insign_deg < $extent[1][$i + 1])
            {
                if ($extent[0][$i] == $p_id)
                {
                    $ret['plus'] += 2;
                    $ret['power'] += 2;
                    $ret['extent'] = 1;
                    $ret['extent_cn'] = '界主';
                }
                $ret['or_extent_planet_id'] = $extent[0][$i];
            }
        }
        // 默认使用欧洲古典占星十分度主星配置  || 印度占星十分度主星
        $decanates = $this->options['decanates'] === 0 ? 4 : 5;
        // 旬主或十度
        for ($i = 0; $i < 3; $i++)
        {
            $min = $i * 10;
            $max = $min + 10;
            if ($p_insign_deg > $min && $p_insign_deg < $max)
            {
                if ($config_ancient[$decanates][$i] == $p_id)
                {
                    ++$ret['plus'];
                    ++$ret['power'];
                    $ret['period'] = 1;
                    $ret['period_cn'] = '旬主';
                }
                $ret['or_period_planet_id'] = $config_ancient[4][$i];
            }
        }

        if ($ret['walls'] === -1 && $ret['promote'] === -1 && $ret['trisection'] === -1 && $ret['extent'] === -1 && $ret['period'] === -1 && $ret['power'] === 0 && $p_id < 7)
        {
            $ret['power'] = -5;
            $ret['migration'] = 1;
            $ret['migration_cn'] = '游走';
        }
        if ($p_id > 6 && $p_id < 9 && $ret['walls'] === -1)
        {
            $ret['power'] = -5;
            $ret['migration'] = 1;
            $ret['migration_cn'] = '游走';
        }
        // 所有星座的29°
        if ($p_insign_deg >= 29) $ret['diversity'] = '岐度';
        else $ret['diversity'] = '';

        // 基本星座（白羊、巨蟹、天秤、摩羯）：0°，13°，26°
        // 固定星座（金牛、狮子、天蝎、水瓶）：9°，21°
        // 变动星座（双子、处女、射手、双鱼）：4°，17°
        if ((in_array($p_insign_id, [1, 4, 7, 10]) && in_array(floor($p_insign_deg), [0, 13, 26]))
            || (in_array($p_insign_id, [2, 5, 8, 11]) && in_array(floor($p_insign_deg), [9, 21]))
            || (in_array($p_insign_id, [3, 6, 9, 12]) && in_array(floor($p_insign_deg), [4, 17])))
            $ret['vital'] = '紧要度数';
        else $ret['vital'] = '';

        // 金牛座的29度、狮子座 6度、射手座 8度
        if (($p_insign_id == 2 && floor($p_insign_deg) == 29)
            || ($p_insign_id == 5 && floor($p_insign_deg) == 6)
            || ($p_insign_id == 9 && floor($p_insign_deg) == 8)
        )
            $ret['defect'] = '缺点度数';
        else $ret['defect'] = '';

        return $ret;
    }

    /**
     * 计算12个宫头  宫神星
     * @param int $insignid
     * @param int $insigndeg
     * @return int
     */
    protected function houseAlmuten($insignid = 0, $insigndeg = 0): int
    {
        $score = [0, 0, 0, 0, 0, 0, 0];// 初始分数为0
        $data = $this->getConfigFromFile('ancient')[$insignid];
        $score[$data[0]] += 5;// 本垣
        if ($data[1] !== '')
        {
            $score[$data[1]] += 4;// 擢升
        }
        $score[$data[2][0]] += 3;// 三分 此处取第一三分主星
        $extent = $data[3][$this->options['bound_type']];

        for ($i = 0; $i < 5; $i++)
        {
            if ($insigndeg > $extent[1][$i] && $insigndeg < $extent[1][$i + 1])
                $score[$extent[0][$i]] += 2;// 界
            if ($i < 3)
            {
                $min = $i * 10;
                $max = $min + 10;
                if ($insigndeg > $min && $insigndeg < $max)
                    ++$score[$data[4][$i]];// 面
            }
        }
        // 分值最高星为宫神星
        return array_search(max($score), $score, true);
    }

    /**
     * 计算得时失时
     * @param null $pid
     * @param int $insignid
     * @param int $inhouseid
     * @param int $sun_in_out
     * @param bool $isDaily 是否为日盛盘
     * @return int
     */
    protected function planetHagy($pid = null, $insignid = 0, $inhouseid = 0, $sun_in_out = 0, $isDaily = false): int
    {
        if ($pid > 6) return -1;// 只计算日月水金火木土0123456
        $day_planet = [0, 5, 6];// 昼行星
        $night_planet = [1, 3, 4];// 夜行星
        if ($pid == 2)
        {
            // 水星东出为昼行星  西入为夜行星
            if ($sun_in_out == 0) $day_planet[] = 2;
            elseif ($sun_in_out == 1) $night_planet[] = 2;
        }
        // 日生盘
        if ($isDaily == true)
        {
            // 得时
            if (in_array($pid, $day_planet) && $insignid % 2 == 1 && $inhouseid > 6) return 0;// 得时
            // 失时
            if (in_array($pid, $night_planet) && $insignid % 2 == 1 && $inhouseid > 6) return 1;// 失时
        } // 夜生盘
        else
        {
            // 得时
            if (in_array($pid, $night_planet) && $insignid % 2 == 0 && $inhouseid > 6) return 0;
            // 失时
            if (in_array($pid, $day_planet) && $insignid % 2 == 0 && $inhouseid > 6) return 1;
        }
        return -1;
    }

    /**
     * 计算行星的东出西入
     * @param int $pid
     * @param int $sunDeg
     * @param int $pDeg
     * @return int|false
     */
    protected function orientalOrOccidentalSun($pid = null, $sunDeg = 0, $pDeg = 0)
    {
        if ($pid > 6 || !$pid) return -1;
        if ($sunDeg > 180)
        {
            $min = $sunDeg - 180;
            $max = $sunDeg;
            if ($pDeg > $min && $pDeg < $max) return 0;// 东出
            if ($pDeg < $min || $pDeg > $max) return 1;// 西入
        } else
        {
            $min = $sunDeg;
            $max = $sunDeg + 180;
            if ($pDeg > $min && $pDeg < $max) return 1;// 西入
            if ($pDeg < $min || $pDeg > $max) return 0;// 东出

        }
        return false;
    }

    /**
     * 计算行星是否在日光下  灼伤 日心
     * @param null $pid
     * @param int $sunDeg
     * @param int $pDeg
     * @return int
     */
    protected function planetSunDist($pid = null, $sunDeg = 0, $pDeg = 0): int
    {
        if ($pid > 6 || !$pid) return -1;
        if (abs($sunDeg - $pDeg) > 270)
        {
            if ($sunDeg > $pDeg)
                $dist = $pDeg + 360 - $sunDeg;
            else
                $dist = $sunDeg + 360 - $pDeg;
        } else
        {
            $dist = abs($sunDeg - $pDeg);
        }
        if ($dist > 17.5) return 0;// 无
        elseif ($dist > 8.5) return 1;// 在日光下
        elseif ($dist > 17 / 60) return 2;// 灼伤
        else return 3;// 日心 日核
    }

    /**
     * 判断行星 喜乐宫
     * @param null $pid
     * @param int $inhouseid
     * @return array
     */
    protected function planetInLikeHouse($pid = null, $inhouseid = 0): ?array
    {
        if ($pid === null || !$inhouseid || $pid > 6) return [-1, -1];
        if ($pid == 0)
            if ($inhouseid == 9) return [1, 9];
            else return [0, 9];
        elseif ($pid == 1)
            if ($inhouseid == 3) return [1, 3];
            else return [0, 3];
        elseif ($pid == 2)
            if ($inhouseid == 1) return [1, 1];
            else return [0, 1];
        elseif ($pid == 3)
            if ($inhouseid == 5) return [1, 5];
            else return [0, 5];
        elseif ($pid == 4)
            if ($inhouseid == 6) return [1, 6];
            else return [0, 6];
        elseif ($pid == 5)
            if ($inhouseid == 11) return [1, 11];
            else return [0, 11];
        else
            if ($inhouseid == 12) return [1, 12];
            else return [0, 12];
    }

    /**
     * 判断行星是否位于燃烧之路
     * @param null $pid 行星id
     * @param int $insignid 行星落座id
     * @param int $insigndeg 行星落在当前星座多少度
     * @return bool|string
     */
    protected function planetInBurnWay($pid = null, $insignid = 0, $insigndeg = 0)
    {
        if ($pid > 6 || $pid === null || !$insignid) return -1;
        if (($insignid == 7 && $insigndeg >= 15) || ($insignid == 8 && $insigndeg <= 15)) return 1;// 燃烧之路
        else return 0;
    }

    /**
     * 计算古典七星-行星映点antipode 与 反映点reflect
     * @param null $pid 行星
     * @param int $pDeg
     * @param array $p
     * @return array|null
     */
    protected function planetAntipode($pid = null, $pDeg = 0, $p = []): ?array
    {
        $orb = 2;
        if ($pid > 6 || $pid === null || empty($p)) return null;
        // 离冬至点即摩羯座0°近
        if (abs($pDeg - 90) > abs($pDeg - 270)) $axisDeg = 540;
        // 离夏至点即巨蟹座0°近
        else $axisDeg = 180;

        $antipode_deg = $axisDeg - $pDeg;
        $reflect_deg = $antipode_deg > 180 ? $antipode_deg - 180 : $antipode_deg + 180;

        $ret['antipode_deg'] = $this->degFormat($antipode_deg);
        $ret['reflect_deg'] = $this->degFormat($reflect_deg);
        $ret['antipode_planet'] = [];
        $ret['reflect_planet'] = [];

        foreach ($p as $i => $d)
        {
            if ($i > MC) continue;
            if (abs($antipode_deg - $d) <= $orb) $ret['antipode_planet'][] = $i;
            if (abs($reflect_deg - $d) <= $orb) $ret['reflect_planet'][] = $i;
        }

        return $ret;
    }

    /**
     * 计算互容接纳
     * @param array $planets
     * @return array
     */
    public function receptOrMutualRecept($planets = []): array
    {
        $ret = [];
        $miscible = [];// 互容
        $accept = [];// 接纳
        // 古典七星
        for ($i = 0; $i <= 5; $i++)
        {
            for ($l = 0; $l <= 6; $l++)
            {
                if (!isset($planets[$i], $planets[$l])) continue;
                $i_ancient = $this->planetInAncient($i, $planets[$l]['in_sign_id'], $planets[$l]['in_sign_deg_e']);
                $l_ancient = $this->planetInAncient($l, $planets[$i]['in_sign_id'], $planets[$i]['in_sign_deg_e']);

                $isPhaseIJ = isset($planets[$i]['phase'][$i . '-' . $l]);

                // 互容
                if ($i_ancient['plus'] > 3 && $l_ancient['plus'] > 3 && $i < $l)
                {
                    $ancient1 = '';
                    if ($i_ancient['walls'] == 1) $ancient1 .= '+本垣';
                    if ($i_ancient['promote'] == 1) $ancient1 .= '+擢升';
                    if ($i_ancient['trisection'] == 1) $ancient1 .= '+三分';
                    if ($i_ancient['extent'] == 1) $ancient1 .= '+界主';
                    if ($i_ancient['period'] == 1) $ancient1 .= '+十度';
                    $ancient1 = mb_substr($ancient1, 1);
                    $ancient2 = '';
                    if ($l_ancient['walls'] == 1) $ancient2 .= '+本垣';
                    if ($l_ancient['promote'] == 1) $ancient2 .= '+擢升';
                    if ($l_ancient['trisection'] == 1) $ancient2 .= '+三分';
                    if ($l_ancient['extent'] == 1) $ancient2 .= '+界主';
                    if ($l_ancient['period'] == 1) $ancient2 .= '+十度';
                    $ancient2 = mb_substr($ancient2, 1);
                    if ($isPhaseIJ)
                    {
                        $have_phase = true;
                    } else
                    {
                        $have_phase = false;
                    }
                    $miscible[] = $i . '-' . $l;
                    $miscible[] = $l . '-' . $i;
                    $ret[2][] = [
                        'id1' => $i,
                        'ancient1' => $ancient2,
                        'id2' => $l,
                        'ancient2' => $ancient1,
                        'phase' => $have_phase,// 是否成相位，有相位互容 || 无相位互容
                        'relation_by' => [
                            'walls1' => $i_ancient['walls'],
                            'promote1' => $i_ancient['promote'],
                            'trisection1' => $i_ancient['trisection'],
                            'extent1' => $i_ancient['extent'],
                            'period1' => $i_ancient['period'],
                            'walls2' => $l_ancient['walls'],
                            'promote2' => $l_ancient['promote'],
                            'trisection2' => $l_ancient['trisection'],
                            'extent2' => $l_ancient['extent'],
                            'period2' => $l_ancient['period'],
                        ],
                        'relation' => '互容',
                        'status' => 2,
                    ];
                } elseif ($isPhaseIJ && $l_ancient['plus'] > 3)
                {
                    // 尚未记录在互容和接纳中
                    if (!in_array($i . '-' . $l, $miscible) && !in_array($i . '-' . $l, $accept))
                    {
                        // 存在相位  接纳
                        $ancient2 = '';
//                        $ancient1 = '';
                        if ($l_ancient['walls'] == 1) $ancient2 .= '+本垣';
                        if ($l_ancient['promote'] == 1) $ancient2 .= '+擢升';
                        if ($l_ancient['trisection'] == 1) $ancient2 .= '+三分';
                        if ($l_ancient['extent'] == 1) $ancient2 .= '+界主';
                        if ($l_ancient['period'] == 1) $ancient2 .= '+十度';
                        $ancient2 = mb_substr($ancient2, 1);

                        $accept[] = $i . '-' . $l;
                        $ret[1][] = [
                            'id1' => $i,
                            'ancient1' => '',
                            'id2' => $l,
                            'ancient2' => $ancient2,
                            'relation_by' => [
                                'walls' => $l_ancient['walls'], 'promote' => $l_ancient['promote'], 'trisection' => $l_ancient['trisection'],
                                'extent' => $l_ancient['extent'], 'period' => $l_ancient['period']
                            ],
                            'relation' => '接纳',
                            'status' => 1,
                        ];
                    }
                } elseif ($isPhaseIJ && $i_ancient['plus'] > 3)
                {
                    // 尚未记录在互容和接纳中
                    if (!in_array($l . '-' . $i, $miscible) && !in_array($l . '-' . $i, $accept))
                    {
                        // 存在相位  接纳
//                        $ancient2 = '';
                        $ancient1 = '';
                        if ($i_ancient['walls'] == 1) $ancient1 .= '+本垣';
                        if ($i_ancient['promote'] == 1) $ancient1 .= '+擢升';
                        if ($i_ancient['trisection'] == 1) $ancient1 .= '+三分';
                        if ($i_ancient['extent'] == 1) $ancient1 .= '+界主';
                        if ($i_ancient['period'] == 1) $ancient1 .= '+十度';
                        $ancient1 = mb_substr($ancient1, 1);
                        $accept[] = $l . '-' . $i;
                        $ret[1][] = [
                            'id1' => $l,
                            'ancient1' => '',
                            'id2' => $i,
                            'ancient2' => $ancient1,
                            'relation_by' => [
                                'walls' => $i_ancient['walls'], 'promote' => $i_ancient['promote'], 'trisection' => $i_ancient['trisection'],
                                'extent' => $i_ancient['extent'], 'period' => $i_ancient['period']
                            ],
                            'relation' => '接纳',
                            'status' => 1,
                        ];
                    }
                }
            }
        }
        // 古典七星
        for ($i = 0; $i <= 6; $i++)
        {
            if (!isset($planets[$i])) continue;
            // 所有星座的29° 岐度
            if ($planets[$i]['ancient']['diversity'])
            {
                $ret[3][] = [
                    'id1' => $i,
                    'id2' => -1,
                    'event' => '位于岐度',
                    'status' => 3,
                ];
            }
            // 紧要度数
            if ($planets[$i]['ancient']['vital'])
            {
                $ret[4][] = [
                    'id1' => $i,
                    'id2' => -1,
                    'event' => '位于紧要度数',
                    'status' => 4,
                ];
            }
            // 缺点度数
            if ($planets[$i]['ancient']['defect'])
            {
                $ret[5][] = [
                    'id1' => $i,
                    'id2' => -1,
                    'event' => '位于缺点度数',
                    'status' => 5,
                ];
            }
            // 映点
            if (!empty($planets[$i]['ancient']['antipode']['antipode_planet']) && $i < $planets[$i]['ancient']['antipode']['antipode_planet'][0])
            {
                $ret[6][] = [
                    'id1' => $i,
                    'id2' => $planets[$i]['ancient']['antipode']['antipode_planet'][0],
                    'event' => '成映点',
                    'status' => 6,
                ];
            }
            // 成反映点
            if (!empty($planets[$i]['ancient']['antipode']['reflect_planet']) && $i < $planets[$i]['ancient']['antipode']['reflect_planet'][0])
            {
                $ret[7][] = [
                    'id1' => $i,
                    'id2' => $planets[$i]['ancient']['antipode']['reflect_planet'][0],
                    'event' => '成反映点',
                    'status' => 7,
                ];
            }
            // 燃烧之路
            if ($planets[$i]['ancient']['burn_way'])
            {
                $ret[8][] = [
                    'id1' => $i,
                    'id2' => -1,
                    'event' => '位于燃烧之路',
                    'status' => 8,
                ];
            }
        }
        return $ret;
    }

    /**
     * 希腊点（阿拉伯点）
     * @param array $planets
     * @param array $houses
     * @param bool $isDaily 是否为日生盘
     * @return array
     */
    protected function getTheArabics($planets = [], $houses = [], $isDaily = true): array
    {
        $asc = $planets[ASC]['deg'] ?? $houses[1]['deg'];
        // 若为日间盘 太阳在地平线以上
        if ($isDaily)
        {
            /**
             * 福点=ASC+月亮-太阳
             */
            $fortune = $this->mod360($asc + $planets[1]['deg'] - $planets[0]['deg']);
            /**
             * 精神点=ASC+太阳-月亮
             */
            $spirit = $this->mod360($asc + $planets[0]['deg'] - $planets[1]['deg']);
            /**
             * 父亲点=Asc+太阳-土星
             */
            $father = $this->mod360($asc + $planets[0]['deg'] - $planets[6]['deg']);
            /**
             * 母亲点=Asc+月亮-金星
             */
            $mother = $this->mod360($asc + $planets[1]['deg'] - $planets[3]['deg']);
            /**
             * 兄弟数量点=Asc+木星-水星
             */
            $brotherNum = $this->mod360($asc + $planets[5]['deg'] - $planets[2]['deg']);
            /**
             * 幸福婚姻点=Asc+7 宫头-金星
             */
            $happyMarriage = $this->mod360($asc + $houses[7]['deg'] - $planets[3]['deg']);
            /**
             * 桃花点=Asc+金星-木星
             */
            $peachBlossom = $this->mod360($asc + $planets[3]['deg'] - $planets[5]['deg']);
            /**
             * 得子时间点=Asc+木星-火星
             */
            $getSunTime = $this->mod360($asc + $planets[5]['deg'] - $planets[4]['deg']);
            /**
             * 儿子点=Asc+太阳-木星
             */
            $son = $this->mod360($asc + $planets[0]['deg'] - $planets[5]['deg']);
            /**
             * 女儿点=Asc+金星-月亮
             */
            $daughter = $this->mod360($asc + $planets[3]['deg'] - $planets[1]['deg']);
            /**
             * 慢性疾病点=Asc+火星-土星
             */
            $chronicDiseases = $this->mod360($asc + $planets[4]['deg'] - $planets[6]['deg']);

            /**
             * 爱神点=ASC-精神点+金星
             */
            $eros = $this->mod360($asc - $spirit + $planets[3]['deg']);
            /**
             * 胜利点=ASC-精神点+木星
             */
            $victory = $this->mod360($asc - $spirit + $planets[5]['deg']);
            /**
             * 必需点=ASC-水星+福点
             */
            $necessity = $this->mod360($asc - $planets[2]['deg'] + $fortune);
            /**
             * 勇气点=ASC-火星+福点
             */
            $courage = $this->mod360($asc - $planets[4]['deg'] + $fortune);
            /**
             * 复仇点/报应点=ASC-土星+福点
             */
            $nemesis = $this->mod360($asc - $planets[6]['deg'] + $fortune);
            /**
             * 旺点=ASC+白羊19°-太阳
             */
            $exaltation = $this->mod360($asc - 19 - $planets[0]['deg']);
        }// 夜间盘
        else
        {
            /**
             * 福点=ASC+太阳-月亮
             */
            $fortune = $this->mod360($asc + $planets[0]['deg'] - $planets[1]['deg']);
            /**
             * 精神点=ASC+月亮-太阳
             */
            $spirit = $this->mod360($asc + $planets[1]['deg'] - $planets[0]['deg']);
            /**
             * 父亲点=Asc+土星-太阳
             */
            $father = $this->mod360($asc + $planets[6]['deg'] - $planets[0]['deg']);
            /**
             * 母亲点=Asc+金星-月亮
             */
            $mother = $this->mod360($asc + $planets[3]['deg'] - $planets[1]['deg']);
            /**
             * 兄弟数量点=Asc+水星-木星
             */
            $brotherNum = $this->mod360($asc + $planets[2]['deg'] - $planets[5]['deg']);
            /**
             * 幸福婚姻点=Asc+金星-7 宫头
             */
            $happyMarriage = $this->mod360($asc + $planets[3]['deg'] - $houses[7]['deg']);
            /**
             * 桃花点=Asc+木星-金星
             */
            $peachBlossom = $this->mod360($asc + $planets[5]['deg'] - $planets[3]['deg']);
            /**
             * 得子时间点=Asc+火星-木星
             */
            $getSunTime = $this->mod360($asc + $planets[4]['deg'] - $planets[5]['deg']);
            /**
             * 儿子点=Asc+木星-太阳
             */
            $son = $this->mod360($asc + $planets[5]['deg'] - $planets[0]['deg']);
            /**
             * 女儿点=Asc+月亮-金星
             */
            $daughter = $this->mod360($asc + $planets[1]['deg'] - $planets[3]['deg']);
            /**
             * 慢性疾病点=Asc+土星-火星
             */
            $chronicDiseases = $this->mod360($asc + $planets[6]['deg'] - $planets[4]['deg']);

            /**
             * 爱神点=ASC-金星+精神点
             */
            $eros = $this->mod360($asc - $planets[3]['deg'] + $spirit);
            /**
             * 胜利点=ASC-木星+精神点
             */
            $victory = $this->mod360($asc - $planets[5]['deg'] + $spirit);
            /**
             * 必需点=ASC-福点+水星
             */
            $necessity = $this->mod360($asc - $fortune + $planets[2]['deg']);
            /**
             * 勇气点=ASC-福点+火星
             */
            $courage = $this->mod360($asc - $fortune + $planets[4]['deg']);
            /**
             * 复仇点/报应点=ASC-福点+土星
             */
            $nemesis = $this->mod360($asc - $fortune + $planets[6]['deg']);
            /**
             * 旺点=ASC+金牛3°-月亮
             */
            $exaltation = $this->mod360($asc + 33 - $planets[1]['deg']);
        }
        /**
         * 当土星处于太阳光束下时（灼伤）：父亲点=Asc+木星-火星
         */
        if ($planets[6]['ancient']['sun_dist'] === 2)
        {
            $father = $this->mod360($asc + $planets[5]['deg'] - $planets[4]['deg']);
        }
        /**
         * 兄弟点=Asc+木星-土星 昼夜相同
         */
        $brother = $this->mod360($asc + $planets[5]['deg'] - $planets[6]['deg']);
        /**
         * 财产点=Asc+2 宫头-2 宫主
         */
        $money = $this->mod360($asc + $houses[2]['deg'] - $planets[$houses[2]['protect_ancient_id']]['deg']);
        /**
         * 男性婚姻点1=Asc+金星-土星 昼夜相同
         */
        $manMarriage1 = $this->mod360($asc + $planets[3]['deg'] - $planets[6]['deg']);
        /**
         * 女性婚姻点1=Asc+土星-金星 昼夜相同
         */
        $womanMarriage1 = $this->mod360($asc + $planets[6]['deg'] - $planets[3]['deg']);
        /**
         * 男性婚姻点2=金星+月亮-太阳 昼夜相同
         */
        $manMarriage2 = $this->mod360($planets[3]['deg'] + $planets[1]['deg'] - $planets[0]['deg']);
        /**
         * 女性婚姻点2=火星+月亮-太阳 昼夜相同
         */
        $womanMarriage2 = $this->mod360($planets[4]['deg'] + $planets[1]['deg'] - $planets[0]['deg']);
        /**
         * 子女点=Asc+土星-木星 昼夜相同
         */
        $children = $this->mod360($asc + $houses[6]['deg'] - $planets[5]['deg']);
        /**
         * 死亡点1=土星+8 宫头-月亮 昼夜相同
         */
        $death1 = $this->mod360($planets[6]['deg'] + $houses[8]['deg'] - $planets[1]['deg']);
        /**
         * 死亡点2=Asc+8 宫头-月亮
         */
        $death2 = $this->mod360($asc + $houses[8]['deg'] - $planets[1]['deg']);
        /**
         * 基础点=ASC+幸运点-精神点
         */
        $base = $this->mod360($asc + $fortune - $spirit);

        $tmp = [
            $spirit, $eros, $victory, $necessity, $courage, $nemesis, $exaltation, $base, 0,
            $father, $mother, $brotherNum, $happyMarriage, $peachBlossom, $getSunTime, $son, $daughter, $chronicDiseases, $brother,
            $money, $manMarriage1, $womanMarriage1, $manMarriage2, $womanMarriage2, $children, $death1, $death2
        ];

        return $this->getArabicsFormat($tmp);
    }

    /**
     * 获取阿拉伯点格式化数据
     * @param array $array
     * @return array
     */
    protected function getArabicsFormat($array = []): array
    {
        $arabics = [
            ['id' => 0, 'name' => '精神点', 'abbreviation' => '精'],
            ['id' => 1, 'name' => '爱神点', 'abbreviation' => '爱'],
            ['id' => 2, 'name' => '胜利点', 'abbreviation' => '胜'],
            ['id' => 3, 'name' => '必需点', 'abbreviation' => '必'],
            ['id' => 4, 'name' => '勇气点', 'abbreviation' => '勇'],
            ['id' => 5, 'name' => '复仇点', 'abbreviation' => '仇'],
            ['id' => 6, 'name' => '旺点', 'abbreviation' => '旺'],
            ['id' => 7, 'name' => '基础点', 'abbreviation' => '基'],
            ['id' => 8, 'name' => '朔望点', 'abbreviation' => '朔'],
            ['id' => 9, 'name' => '父亲点', 'abbreviation' => '父'],
            ['id' => 10, 'name' => '母亲点', 'abbreviation' => '母'],
            ['id' => 11, 'name' => '兄弟数量点', 'abbreviation' => '兄1'],
            ['id' => 12, 'name' => '幸福婚姻点', 'abbreviation' => '婚3'],
            ['id' => 13, 'name' => '桃花点', 'abbreviation' => '桃'],
            ['id' => 14, 'name' => '得子时间点', 'abbreviation' => '子1'],
            ['id' => 15, 'name' => '儿子点', 'abbreviation' => '儿'],
            ['id' => 16, 'name' => '女儿点', 'abbreviation' => '女'],
            ['id' => 17, 'name' => '慢性疾病点', 'abbreviation' => '疾'],
            ['id' => 18, 'name' => '兄弟点', 'abbreviation' => '兄'],
            ['id' => 19, 'name' => '财产点', 'abbreviation' => '财'],
            ['id' => 20, 'name' => '男性婚姻点1', 'abbreviation' => '婚1'],
            ['id' => 21, 'name' => '女性婚姻点1', 'abbreviation' => '婚1'],
            ['id' => 22, 'name' => '男性婚姻点2', 'abbreviation' => '婚2'],
            ['id' => 23, 'name' => '女性婚姻点2', 'abbreviation' => '婚2'],
            ['id' => 24, 'name' => '子女点', 'abbreviation' => '子'],
            ['id' => 25, 'name' => '死亡点1', 'abbreviation' => '死1'],
            ['id' => 26, 'name' => '死亡点2', 'abbreviation' => '死2'],
        ];

        $result = [];

        if (!empty($array))
        {
            foreach ($array as $aid => $deg)
            {
                $result[] = [
                    'id' => $aid,
                    'name' => $arabics[$aid]['name'],
                    'abbreviation' => $arabics[$aid]['abbreviation'],
                    'deg' => $this->degFormat($deg),
                    'is_draw' => isset($this->options['arabics'][$aid][0]) && $this->options['arabics'][$aid][0] === 1,
                    'in_sign_deg' => $this->inSignDeg($deg),
                    'in_sign_id' => InWhichSign($deg),
                ];
            }
        }
        return $result;
    }

    /**
     * 对度数进行格式化
     * @param float $deg 度数
     * @param int $decimails 保留的小数位数
     * @return float
     */
    protected function degFormat($deg = 0.0, $decimails = 6): float
    {
        return (float)number_format($deg, $decimails);
    }

    /**
     * 相位出入相
     * @param $asp int 相位度数
     * @param $deg1 float 行星度数1
     * @param $deg2 float 行星度数2
     * @param $speed1  float 速度1
     * @param $speed2 float 速度2
     * @param int $phase_orb 实际相位容许度
     * @param int $vs 1=>行星1为本命 2=> 行星2为本命     本命盘速度为0
     * @return bool true 为入相  false 为出相
     */
    protected function phaseInOrOut($asp, $deg1, $deg2, $speed1, $speed2, $phase_orb = 0, $vs = 0): bool
    {
        // VS 本命盘计算出入相位
        if ($vs)
        {
            if ($vs === 1)
            {
                $speed1 = 0.0;
            } else
            {
                $speed2 = 0.0;
            }
        }
        // 方向 1 =>顺行  -1 => 逆行
        $direction = 1;

        if (abs($speed1) > abs($speed2))
        {
            // 计算速度慢的一方的精准成相的度数
            $accurate_a = $this->mod360($deg2 + $asp);
            $accurate_b = $this->mod360($deg2 - $asp);
            $caclDeg = $deg1;

            if ($speed1 < 0)
            {
                $direction = -1;
            }
        } else
        {
            // 计算速度慢的一方的精准成相的度数
            $accurate_a = $this->mod360($deg1 + $asp);
            $accurate_b = $this->mod360($deg1 - $asp);
            $caclDeg = $deg2;

            if ($speed2 < 0)
            {
                $direction = -1;
            }
        }
        $accurate_a = $this->degFormat($accurate_a, 7);
        $accurate_b = $this->degFormat($accurate_b, 7);
        $change = $this->degFormat($this->mod360($caclDeg + $phase_orb * $direction), 7);

//        if ($change - $accurate_a <= 0.0001 || $change - $accurate_b <= 0.0001)
//        {
//            return true;
//        }
        return $change == $accurate_a || $change == $accurate_b;
//        if ($change == $accurate_a || $change == $accurate_b)
//        {
//            return true;
//        }
//
//        return false;
    }

    /**
     * 获取行星结构
     * @param array $base_data
     * @param bool $is_in
     * @return array
     */
    public function getStructure($base_data = [], $is_in = false): array
    {
        if (empty($base_data)) return [];
        $base_data['structure'] = $this->aspectPatterns($base_data, $is_in);
        $base_data['structure']['asterism'] = $this->asterism($base_data);
        if ($this->options['version'] === 1)
        {
            $base_data['structure']['midpoint'] = $this->planetMidpoint($base_data);
        } elseif ($this->options['version'] === 2)
        {
            $midPoint = $this->getPlanetMidpointV2($base_data);
            $base_data['structure']['midpoint_phase'] = $midPoint['midpoint_phase'];
            $base_data['structure']['midpoint'] = $midPoint['midpoint'];
        }
        $base_data['structure']['finger'] = $this->godFinger($base_data);
        return $base_data;
    }

    /**
     * 大三角
     * 120°-120°-120°
     * 小三角 与两颗星都成60度的这颗星称为顶星
     * 120°-60°-60°
     * T三角 与两星成90度的星体称为“T顶点”
     * 180°-90°-90°
     * 桥三角：两颗星180度，同时有第三颗星与两星分别成60度和120度。该星称为桥星。
     * 180°-60°-120°
     * 大十字：四颗星组成一个正四方形，每颗星都与另外两颗成90度（可以认为是在T三角基础上，加上一颗与T顶点对冲的行星）
     * 180°-90°-90°-180°
     * 大信封：桥三角的桥星对面多出一颗对冲的行星
     * 大风筝：大三角顶星的对面，多出一颗与它成180度的行星
     * @param array $base_data
     * @param bool $is_in
     * @return array
     */
    protected function aspectPatterns($base_data = [], $is_in = false): array
    {
        $ret = [
            'trine' => [],
            'small_triangle' => [],
            'kite' => [],
            't_square' => [],
            'cross' => [],
            'bridge_triangle' => [],
            'envelop' => [],
        ];
        for ($i = 0; $i < 10; $i++)
        {
            $a = $base_data['planets'][$i];
            $phasei = $a['phase'];
            for ($j = 0; $j < 10; $j++)
            {
                $b = $base_data['planets'][$j];
                $phasej = $b['phase'];
                $isPhaseIJ = isset($phasei[$i . '-' . $j]);
                $isILessJ = $i < $j;
                // 大三角 + 小三角
                if ($isPhaseIJ && $phasei[$i . '-' . $j]['phase_e'] == 120 && $isILessJ)
                {
                    for ($z = 0; $z < 10; $z++)
                    {
                        $c = $base_data['planets'][$z];
                        $isPhaseIZ = isset($phasei[$i . '-' . $z]);
                        $isPhaseJZ = isset($phasej[$i . '-' . $z]);
                        $isjLessZ = $j < $z;
                        // 大三角
                        if ($isPhaseIZ && $phasei[$i . '-' . $z]['phase_e'] == 120 && $isjLessZ
                            && $isPhaseJZ && $phasej[$j . '-' . $z]['phase_e'] == 120)
                        {
                            if ($is_in) $ret['trine'][] = [$i, $j, $z];
                            else $ret['trine'][] = [
                                [
                                    'id' => $i,
                                    'in_sign_id' => $a['in_sign_id'],
                                    'in_house_id' => $a['in_house_id'],
                                ],
                                [
                                    'id' => $j,
                                    'in_sign_id' => $b['in_sign_id'],
                                    'in_house_id' => $b['in_house_id'],
                                ],
                                [
                                    'id' => $z,
                                    'in_sign_id' => $c['in_sign_id'],
                                    'in_house_id' => $c['in_house_id'],
                                ],
                            ];
                            for ($y = 0; $y < 10; $y++)
                            {
                                $d = $base_data['planets'][$y];
                                $phasey = $d['phase'];
                                $isPhaseYZ = isset($phasey[$y . '-' . $z]);
                                // 大风筝：大三角顶星的对面，多出一颗与它成180度的行星
                                if ($isPhaseYZ && $phasey[$y . '-' . $z]['phase_e'] == 180)
                                {
                                    if ($is_in) $ret['kite'][] = [$i, $j, $z, $y];
                                    else $ret['kite'][] = [
                                        [
                                            'id' => $i,
                                            'in_sign_id' => $a['in_sign_id'],
                                            'in_house_id' => $a['in_house_id'],
                                            'top' => false,
                                        ],
                                        [
                                            'id' => $j,
                                            'in_sign_id' => $b['in_sign_id'],
                                            'in_house_id' => $b['in_house_id'],
                                            'top' => false,
                                        ],
                                        [
                                            'id' => $z,
                                            'in_sign_id' => $c['in_sign_id'],
                                            'in_house_id' => $c['in_house_id'],
                                            'top' => false,
                                        ],
                                        [
                                            'id' => $y,
                                            'in_sign_id' => $d['in_sign_id'],
                                            'in_house_id' => $d['in_house_id'],
                                            'top' => true,
                                        ],
                                    ];
                                }
                            }
                        } // 小三角
                        elseif ($isPhaseIZ && $phasei[$i . '-' . $z]['phase_e'] == 60 && $isjLessZ
                            && $isPhaseJZ && $phasej[$j . '-' . $z]['phase_e'] == 60)
                        {
                            if ($is_in) $ret['small_triangle'][] = [$i, $j, $z];
                            else
                                $ret['small_triangle'][] = [
                                    [
                                        'id' => $i,
                                        'in_sign_id' => $a['in_sign_id'],
                                        'in_house_id' => $a['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $j,
                                        'in_sign_id' => $b['in_sign_id'],
                                        'in_house_id' => $b['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $z,
                                        'in_sign_id' => $c['in_sign_id'],
                                        'in_house_id' => $c['in_house_id'],
                                        'top' => true,
                                    ]
                                ];
                        }

                    }
                } // T三角 + 大十字
                elseif ($isPhaseIJ && $phasei[$i . '-' . $j]['phase_e'] == 180 && $isILessJ)
                {
                    for ($z = 0; $z < 10; $z++)
                    {
                        $c = $base_data['planets'][$z];
                        $phasez = $c['phase'];
                        $isPhaseIZ = isset($phasei[$i . '-' . $z]);
                        $isPhaseJZ = isset($phasej[$i . '-' . $z]);
                        $isPhaseZI = isset($phasez[$z . '-' . $i]);
                        $isPhaseZJ = isset($phasez[$z . '-' . $j]);
                        $isIDifferentZ = $i !== $z;
                        $isJDifferentZ = $j !== $z;
                        // T三角
                        if ($isPhaseIZ && $phasei[$i . '-' . $z]['phase_e'] == 90 && $isIDifferentZ
                            && $isPhaseJZ && $phasej[$j . '-' . $z]['phase_e'] == 90 && $isJDifferentZ
                        )
                        {
                            if ($is_in) $ret['t_square'][] = [$i, $j, $z];
                            else
                                $ret['t_square'][] = [
                                    [
                                        'id' => $i,
                                        'in_sign_id' => $a['in_sign_id'],
                                        'in_house_id' => $a['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $j,
                                        'in_sign_id' => $b['in_sign_id'],
                                        'in_house_id' => $b['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $z,
                                        'in_sign_id' => $c['in_sign_id'],
                                        'in_house_id' => $c['in_house_id'],
                                        'top' => true,
                                    ]
                                ];
                            for ($y = 0; $y < 10; $y++)
                            {
                                $d = $base_data['planets'][$y];
                                $phasey = $d['phase'];
                                $isPhaseYZ = isset($phasey[$y . '-' . $z]);
                                $isPhaseYI = isset($phasey[$y . '-' . $i]);
                                $isPhaseYJ = isset($phasey[$y . '-' . $j]);
                                // 大十字
                                if ($isPhaseYZ && $phasey[$y . '-' . $z]['phase_e'] == 180 && $i < $z
                                    && $isPhaseYJ && $phasey[$y . '-' . $j]['phase_e'] == 90
                                    && $isPhaseYI && $phasey[$y . '-' . $i]['phase_e'] == 90 && $z < $y
                                )
                                {
                                    if ($is_in) $ret['cross'][] = [$i, $j, $z];
                                    else
                                        $ret['cross'][] = [
                                            [
                                                'id' => $i,
                                                'in_sign_id' => $a['in_sign_id'],
                                                'in_house_id' => $a['in_house_id'],
                                                'top' => false,
                                            ],
                                            [
                                                'id' => $j,
                                                'in_sign_id' => $b['in_sign_id'],
                                                'in_house_id' => $b['in_house_id'],
                                                'top' => false,
                                            ],
                                            [
                                                'id' => $z,
                                                'in_sign_id' => $c['in_sign_id'],
                                                'in_house_id' => $c['in_house_id'],
                                                'top' => false,
                                            ],
                                            [
                                                'id' => $y,
                                                'in_sign_id' => $d['in_sign_id'],
                                                'in_house_id' => $d['in_house_id'],
                                                'top' => true,
                                            ],
                                        ];
                                }
                            }
                        }
                        // 桥三角 两颗星180度，同时有第三颗星与两星分别成60度和120度。该星称为桥星。
                        // 大信封：桥三角的桥星对面多出一颗对冲的行星
                        elseif ($isIDifferentZ && $isJDifferentZ &&
                            (($isPhaseZI && $isPhaseZJ
                                && (($phasez[$z . '-' . $i]['phase_e'] == 120 && $phasez[$z . '-' . $j]['phase_e'] == 60)
                                    || ($phasez[$z . '-' . $i]['phase_e'] == 60 && $phasez[$z . '-' . $j]['phase_e'] == 120))))
                        )
                        {
                            if ($is_in) $ret['bridge_triangle'][] = [$i, $j, $z];
                            else
                                $ret['bridge_triangle'][] = [
                                    [
                                        'id' => $i,
                                        'in_sign_id' => $a['in_sign_id'],
                                        'in_house_id' => $a['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $j,
                                        'in_sign_id' => $b['in_sign_id'],
                                        'in_house_id' => $b['in_house_id'],
                                        'top' => false,
                                    ],
                                    [
                                        'id' => $z,
                                        'in_sign_id' => $c['in_sign_id'],
                                        'in_house_id' => $c['in_house_id'],
                                        'top' => true,
                                    ],
                                ];
                            for ($y = 0; $y < 10; $y++)
                            {
                                $d = $base_data['planets'][$y];
                                $phasey = $d['phase'];
                                $isPhaseYZ = isset($phasey[$y . '-' . $z]);
                                // 大信封
                                if ($isPhaseYZ && $phasey[$y . '-' . $z]['phase_e'] == 180
                                    && $z < $y && $i < $z
                                )
                                {
                                    if ($is_in) $ret['envelop'][] = [$i, $j, $z];
                                    else
                                        $ret['envelop'][] = [
                                            [
                                                'id' => $i,
                                                'in_sign_id' => $a['in_sign_id'],
                                                'in_house_id' => $a['in_house_id'],
                                            ],
                                            [
                                                'id' => $j,
                                                'in_sign_id' => $b['in_sign_id'],
                                                'in_house_id' => $b['in_house_id'],
                                            ],
                                            [
                                                'id' => $z,
                                                'in_sign_id' => $c['in_sign_id'],
                                                'in_house_id' => $c['in_house_id'],
                                            ],
                                            [
                                                'id' => $y,
                                                'in_sign_id' => $d['in_sign_id'],
                                                'in_house_id' => $d['in_house_id'],
                                            ],
                                        ];
                                }
                            }
                        }
                    }
                }
            }
        }
        return $ret;
    }

    /**
     * 星群：三颗以上行星聚拢，称作星群（不计算小行星）
     * 紧密星群1：三颗以上行星，彼此合相
     * 疏松星群2：三颗以上行星，不满足紧密星群条件，但每颗星都有一个合相
     * 分散星群3：三颗以上行星，不满足前两种，但位于同一星座或同一宫位
     * @param array $base_data
     * @return array
     */
    protected function asterism($base_data = []): array
    {
        $ret = [];
        $signs_arr = [];
        $houses_arr = [];
        for ($i = 0; $i < 10; $i++)
        {
            $signs_arr[$base_data['planets'][$i]['in_sign_id']][] = $i;
            $houses_arr[$base_data['planets'][$i]['in_house_id']][] = $i;
        }
        $check = [];
        for ($i = 0; $i < 10; $i++)
        {
            $a = $base_data['planets'][$i];

            $phasei = $a['phase'];
            for ($j = 0; $j < 10; $j++)
            {
                $b = $base_data['planets'][$j];
                $phasej = $b['phase'];
                $isPhaseIJ = isset($phasei[$i . '-' . $j]);
                if ($isPhaseIJ && $phasei[$i . '-' . $j]['phase_e'] == 0 && $i < $j)
                {
                    for ($k = 0; $k < 10; $k++)
                    {
                        $c = $base_data['planets'][$k];
                        $phasek = $c['phase'];
                        $isPhaseIK = isset($phasei[$i . '-' . $k]);
                        $isPhaseJK = isset($phasei[$j . '-' . $k]);
                        $isJLessK = $j < $k;
                        // 紧密星群：三颗以上行星，彼此合相
                        if ($isPhaseIK && $phasei[$i . '-' . $k]['phase_e'] == 0 && $isJLessK
                            && $isPhaseJK && $phasej[$j . '-' . $k]['phase_e'] == 0
                        )
                        {
                            $check_str = $i . '-' . $j . '-' . $k;
                            if (!$this->checkIn($check_str, $check))
                            {
                                $check[] = $check_str;
                                $ret[1][] = [
                                    [
                                        'id' => $i,
                                        'in_sign_id' => $a['in_sign_id'],
                                        'in_house_id' => $a['in_house_id'],
                                    ],
                                    [
                                        'id' => $j,
                                        'in_sign_id' => $b['in_sign_id'],
                                        'in_house_id' => $b['in_house_id'],
                                    ],
                                    [
                                        'id' => $k,
                                        'in_sign_id' => $c['in_sign_id'],
                                        'in_house_id' => $c['in_house_id'],
                                    ],
                                ];
                            }

                        } // 疏松星群：三颗以上行星，不满足紧密星群条件，但每颗星都有一个合相
                        elseif ($isJLessK &&
                            (($isPhaseIK && $phasei[$i . '-' . $k]['phase_e'] == 0)
                                || ($isPhaseJK && $phasej[$j . '-' . $k]['phase_e'] == 0))
                        )
                        {
                            $ss = 0;
                            for ($g = 0; $g < 10; $g++)
                            {
                                $d = $base_data['planets'][$g];
                                $isPhaseIG = isset($phasei[$i . '-' . $g]);
                                $isPhaseJG = isset($phasei[$j . '-' . $g]);
                                $isPhaseKG = isset($phasei[$k . '-' . $g]);
                                if ($k < $g &&
                                    (($isPhaseIG && $phasei[$i . '-' . $g]['phase_e'] == 0)
                                        || ($isPhaseJG && $phasej[$j . '-' . $g]['phase_e'] == 0)
                                        || ($isPhaseKG && $phasek[$k . '-' . $g]['phase_e'] == 0))
                                )
                                {
                                    $check_str = $i . '-' . $j . '-' . $k . '-' . $g;
                                    if (!$this->checkIn($check_str, $check))
                                    {
                                        $check[] = $check_str;
                                        $ss = 1;
                                        $ret[2][] = [
                                            [
                                                'id' => $i,
                                                'in_sign_id' => $a['in_sign_id'],
                                                'in_house_id' => $a['in_house_id'],
                                            ],
                                            [
                                                'id' => $j,
                                                'in_sign_id' => $b['in_sign_id'],
                                                'in_house_id' => $b['in_house_id'],
                                            ],
                                            [
                                                'id' => $k,
                                                'in_sign_id' => $c['in_sign_id'],
                                                'in_house_id' => $c['in_house_id'],
                                            ],
                                            [
                                                'id' => $g,
                                                'in_sign_id' => $d['in_sign_id'],
                                                'in_house_id' => $d['in_house_id'],
                                            ],
                                        ];
                                    }
                                }
                            }
                            if ($ss === 0)
                            {
                                $check_str = $i . '-' . $j . '-' . $k;
                                if (!$this->checkIn($check_str, $check))
                                {
                                    $check[] = $check_str;
                                    $ret[2][] = [
                                        [
                                            'id' => $i,
                                            'in_sign_id' => $a['in_sign_id'],
                                            'in_house_id' => $a['in_house_id'],
                                        ],
                                        [
                                            'id' => $j,
                                            'in_sign_id' => $b['in_sign_id'],
                                            'in_house_id' => $b['in_house_id'],
                                        ],
                                        [
                                            'id' => $k,
                                            'in_sign_id' => $c['in_sign_id'],
                                            'in_house_id' => $c['in_house_id'],
                                        ],
                                    ];
                                }
                            }
                        }
                    }
                }
            }
        }
        // 分散星群 ：三颗或以上行星，不满足前两种，但位于同一星座或同一宫位
        for ($i_i = 1; $i_i < 13; $i_i++)
        {
            $c_s = (isset($signs_arr[$i_i]) && is_countable($signs_arr[$i_i])) ? count($signs_arr[$i_i]) : 0;
            $c_h = (isset($houses_arr[$i_i]) && is_countable($houses_arr[$i_i])) ? count($houses_arr[$i_i]) : 0;
            // 位于同一星座
            if ($c_s >= 3)
            {
                $a = $base_data['planets'][$signs_arr[$i_i][0]];
                $b = $base_data['planets'][$signs_arr[$i_i][1]];
                $c = $base_data['planets'][$signs_arr[$i_i][2]];
                $data = [
                    [
                        'id' => $signs_arr[$i_i][0],
                        'in_sign_id' => $a['in_sign_id'],
                        'in_house_id' => $a['in_house_id'],
                    ],
                    [
                        'id' => $signs_arr[$i_i][1],
                        'in_sign_id' => $b['in_sign_id'],
                        'in_house_id' => $b['in_house_id'],
                    ],
                    [
                        'id' => $signs_arr[$i_i][2],
                        'in_sign_id' => $c['in_sign_id'],
                        'in_house_id' => $c['in_house_id'],
                    ]
                ];
                $check_str = $signs_arr[$i_i][0] . '-' . $signs_arr[$i_i][1] . '-' . $signs_arr[$i_i][2];
                if ($c_s > 3)
                {
                    for ($s = 3; $s < $c_s; $s++)
                    {
                        $check_str .= '-' . $signs_arr[$i_i][$s];
                        $temp = $base_data['planets'][$signs_arr[$i_i][$s]];
                        $data[] = [
                            'id' => $signs_arr[$i_i][$s],
                            'in_sign_id' => $temp['in_sign_id'],
                            'in_house_id' => $temp['in_house_id'],
                        ];
                    }
                }
                if (!$this->checkIn($check_str, $check))
                {
                    $data = $this->resetSort($check_str, $data, 'in_house_id', $base_data);
                    // 同一星座的  按照宫位id排序
                    $check[] = $check_str;
                    $ret[3][] = $data;
                    unset($signs_arr[$i_i]);
                }
            }
            // 位于同一宫位
            if ($c_h >= 3)
            {
                $a = $base_data['planets'][$houses_arr[$i_i][0]];
                $b = $base_data['planets'][$houses_arr[$i_i][1]];
                $c = $base_data['planets'][$houses_arr[$i_i][2]];
                $data = [
                    [
                        'id' => $houses_arr[$i_i][0],
                        'in_sign_id' => $a['in_sign_id'],
                        'in_house_id' => $a['in_house_id'],
                    ],
                    [
                        'id' => $houses_arr[$i_i][1],
                        'in_sign_id' => $b['in_sign_id'],
                        'in_house_id' => $b['in_house_id'],
                    ],
                    [
                        'id' => $houses_arr[$i_i][2],
                        'in_sign_id' => $c['in_sign_id'],
                        'in_house_id' => $c['in_house_id'],
                    ]
                ];
                $check_str = $houses_arr[$i_i][0] . '-' . $houses_arr[$i_i][1] . '-' . $houses_arr[$i_i][2];
                if ($c_h > 3)
                {
                    for ($s = 3; $s < $c_h; $s++)
                    {

                        $check_str .= '-' . $houses_arr[$i_i][$s];
                        $temp = $base_data['planets'][$houses_arr[$i_i][$s]];
                        $data[] = [
                            'id' => $houses_arr[$i_i][$s],
                            'in_sign_id' => $temp['in_sign_id'],
                            'in_house_id' => $temp['in_house_id'],
                        ];
                    }
                }
                if (!$this->checkIn($check_str, $check))
                {
                    $data = $this->resetSort($check_str, $data, 'in_sign_id', $base_data);
                    // 同一宫位的  按照星座id排序
                    unset($houses_arr[$i_i]);
                    $check[] = $check_str;
                    $ret[3][] = $data;

                }
            }
        }

        return $ret;
    }

    /**
     * 计算行星中点(包括四轴)
     * @param array $base_data
     * @return array
     */
    protected function planetMidpoint($base_data = []): array
    {
        $ret = [];
        for ($i = 0; $i < 10; $i++)
        {
            $a = $base_data['planets'][$i];

            $deg1 = $a['deg'];
            for ($j = $i + 1; $j < 10; $j++)
            {
                $b = $base_data['planets'][$j];
                $deg2 = $b['deg'];
                $mid = ($deg1 + $deg2) / 2;// 中点度数 (A+B)/2
                $mid180 = $mid < 180 ? $mid + 180 : $mid - 180;
                $diffMid = abs($deg1 - $mid);
                $diffMid = $diffMid > 180 ? 360 - $diffMid : $diffMid;
                $diffMid180 = abs($deg1 - $mid180);
                $diffMid180 = $diffMid180 > 180 ? 360 - $diffMid180 : $diffMid180;
                // 处理行星中点 使用 中点类型进行处理
                if (($this->options['mid_type'] === 0 && $diffMid > $diffMid180)
                    || ($this->options['mid_type'] === 1 && $diffMid < $diffMid180))
                {
                    $mid = $mid180;
                }
                for ($k = 0; $k < 10; $k++)
                {
                    $c = $base_data['planets'][$k];
                    $deg3 = $c['deg'];
                    $diff = abs($deg3 - $mid); // 计算相差度数
                    if ($diff > 180) $diff = 360 - $diff;
                    // 判断是否与行星形成 0°/90°/180°相位
                    if ($i !== $k && $j !== $k
                        && (($diff <= 1) || ($diff > 89 && $diff < 91) || ($diff > 179 && $diff < 181)))
                    {
                        $ret[] = [
                            'id1' => $i,
                            'in_sign_id1' => $a['in_sign_id'],
                            'in_house_id1' => $a['in_house_id'],
                            'id2' => $j,
                            'in_sign_id2' => $b['in_sign_id'],
                            'in_house_id2' => $b['in_house_id'],
                            'id3' => $k,
                            'in_sign_id3' => $c['in_sign_id'],
                            'in_house_id3' => $c['in_house_id'],
                            'asp' => $this->degFormat($diff),
                        ];
                    }
                }
                [$asc, $mc] = [$base_data['houses'][1], $base_data['houses'][10]];
//                $asc = $base_data['houses'][1];
//                $mc = $base_data['houses'][10];
                $asc_deg = $asc['deg'];
                $mc_deg = $mc['deg'];
                $axis = [17 => $asc_deg, 20 => $mc_deg];
                foreach ($axis as $ak => $ax)
                {
                    $diff_axis = abs($ax - $mid); // 计算相差度数
                    if ($diff_axis > 180) $diff_axis = 360 - $diff_axis;
                    if (($diff_axis <= 1) || ($diff_axis > 89 && $diff_axis < 91) || ($diff_axis > 179 && $diff_axis < 181))
                    {
                        $insign = $inhouse = null;
                        if ($ak === ASC)
                        {
//                            $name3 = '上升';
                            $insign = $asc['in_sign_id'];
                            $inhouse = 1;
//                        }
//                        if($ak==18)
//                        {
//                            $name3 = '天底';
//                            $insign = $ic['in_sign_id'];
//                            $inhouse = 4;
//                        }
//                        if($ak==19)
//                        {
//                            $name3 = '下降';
//                            $insign = $des['in_sign_id'];
//                            $inhouse = 7;
                        }
                        if ($ak === MC)
                        {
//                            $name3 = '天顶';
                            $insign = $mc['in_sign_id'];
                            $inhouse = 10;
                        }
                        $ret[] = [
                            'id1' => $i,
                            'in_sign_id1' => $a['in_sign_id'],
                            'in_house_id1' => $a['in_house_id'],
                            'id2' => $j,
                            'in_sign_id2' => $b['in_sign_id'],
                            'in_house_id2' => $b['in_house_id'],
                            'id3' => $ak,
                            'in_sign_id3' => $insign,
                            'in_house_id3' => $inhouse,
                            'asp' => $this->degFormat($diff_axis),
//                            'output'=>$a['name_whole'].' + '.$b['name_whole'].' = '.$name3,
                        ];
                    }
                }
            }
        }
        return $ret;
    }

    /**
     * 计算行星中点（十大行星）
     * @param array $base_data
     * @return array
     */
    protected function getPlanetMidpointV2($base_data = []): array
    {
        $result = ['midpoint_phase' => [], 'midpoint' => []];

        $configAncient = $this->getConfigFromFile('ancient');
        $boundType = $this->options['bound_type'];

        $asc = $base_data['planets'][ASC];
        $mc = $base_data['planets'][MC];
        $asc_deg = $asc['deg'];
        $mc_deg = $mc['deg'];
        $axis = [17 => $asc_deg, 20 => $mc_deg];

        for ($i = 0; $i < 10; $i++)
        {
            $a = $base_data['planets'][$i];

            $deg1 = $a['deg'];
            for ($j = $i + 1; $j < 10; $j++)
            {
                $b = $base_data['planets'][$j];
                $deg2 = $b['deg'];
                $mid = ($deg1 + $deg2) / 2;// 中点度数 (A+B)/2
                $mid180 = $mid < 180 ? $mid + 180 : $mid - 180;
                $diffMid = abs($deg1 - $mid);
                $diffMid = $diffMid > 180 ? 360 - $diffMid : $diffMid;
                $diffMid180 = abs($deg1 - $mid180);
                $diffMid180 = $diffMid180 > 180 ? 360 - $diffMid180 : $diffMid180;
                // 处理行星中点 使用 中点类型进行处理
                if (($this->options['mid_type'] === 0 && $diffMid > $diffMid180)
                    || ($this->options['mid_type'] === 1 && $diffMid < $diffMid180))
                {
                    $mid = $mid180;
                }

                for ($k = 0; $k < 10; $k++)
                {
                    $c = $base_data['planets'][$k];
                    $deg3 = $c['deg'];
                    $diff = abs($deg3 - $mid); // 计算相差度数
                    if ($diff > 180) $diff = 360 - $diff;
                    // 判断是否与行星形成 0°/60°/90°/120°/180°相位
                    if ($i !== $k && $j !== $k)
                    {
                        if ($diff <= 1)
                        {
                            $phase = 0;
                            $orb = $diff;
                        } elseif ($diff >= 59 && $diff <= 61)
                        {
                            $phase = 60;
                            $orb = abs(60 - $diff);
                        } elseif ($diff >= 89 && $diff <= 91)
                        {
                            $phase = 90;
                            $orb = abs(90 - $diff);
                        } elseif ($diff >= 119 && $diff <= 121)
                        {
                            $phase = 120;
                            $orb = abs(120 - $diff);
                        } elseif ($diff >= 179 && $diff <= 181)
                        {
                            $phase = 180;
                            $orb = abs(180 - $diff);
                        } else
                        {
                            $orb = 0;
                            $phase = -1;
                        }

                        if ($phase >= 0)
                        {
                            if (!isset($result['midpoint_phase'][$k]['planet_id']))
                            {
                                $result['midpoint_phase'][$k]['planet_id'] = $k;
                            }
                            $result['midpoint_phase'][$k]['phase_info'][] = [
                                'id1' => $i,
                                'id2' => $j,
                                'phase_deg' => $phase,
                                'allowedness' => $this->degFormat($orb, 3)
                            ];
                        }
                    }
                }

                $midInSign = (int)ceil($mid / 29.99999999);

                if ($midInSign < 1) $midInSign = 1;
                elseif ($midInSign > 12) $midInSign = 12;

                $midInSignDeg = floor($mid - ($midInSign - 1) * 30);

                $midInSignGrade = (int)round(($mid - ($midInSign - 1) * 30 - $midInSignDeg) * 60);

                $config_ancient = $configAncient[$midInSign];

                $extent = $config_ancient[3][$boundType];

                $midInSignExtend = -1;

                for ($n = 0; $n < 5; $n++)
                {
                    if ($midInSignDeg >= $extent[1][$n] && $midInSignDeg < $extent[1][$n + 1])
                    {
                        $midInSignExtend = $extent[0][$n];
                    }
                }

                /**
                 * 星座ID [1,12]
                 * 二分法 0=>阴 1=>阳
                 * 三分法 0=>基本 1=>固定 2=>变动
                 * 四分法 0=>火 1=>土 2=>风 3=>水
                 */
                $two = $midInSign % 2;
                $three = $midInSign % 3 - 1;
                $four = $midInSign % 4 - 1;

                $two = $two !== 1 ? 0 : 1;
                $three = $three < 0 ? 2 : $three;
                $four = $four < 0 ? 3 : $four;

                $result['midpoint'][] = [
                    'id1' => $i,
                    'id2' => $j,
                    'deg' => $midInSignDeg,
                    'grade' => $midInSignGrade,
                    'sign_id' => $midInSign,
                    'extent' => $midInSignExtend,
                    'two' => $two,
                    'three' => $three,
                    'four' => $four,
                ];

                foreach ($axis as $ak => $ax)
                {
                    $diff_axis = abs($ax - $mid); // 计算相差度数
                    if ($diff_axis > 180) $diff_axis = 360 - $diff_axis;

                    if ($diff_axis <= 1)
                    {
                        $phase = 0;
                        $orb = $diff_axis;
                    } elseif ($diff_axis >= 59 && $diff_axis <= 61)
                    {
                        $phase = 60;
                        $orb = abs(60 - $diff_axis);
                    } elseif ($diff_axis >= 89 && $diff_axis <= 91)
                    {
                        $phase = 90;
                        $orb = abs(90 - $diff_axis);
                    } elseif ($diff_axis >= 119 && $diff_axis <= 121)
                    {
                        $phase = 120;
                        $orb = abs(120 - $diff_axis);
                    } elseif ($diff_axis >= 179 && $diff_axis <= 181)
                    {
                        $phase = 180;
                        $orb = abs(180 - $diff_axis);
                    } else
                    {
                        $orb = 0;
                        $phase = -1;
                    }

                    if ($phase >= 0)
                    {
                        if (!isset($result['midpoint_phase'][$ak]['planet_id']))
                        {
                            $result['midpoint_phase'][$ak]['planet_id'] = $ak;
                        }
                        $result['midpoint_phase'][$ak]['phase_info'][] = [
                            'id1' => $i,
                            'id2' => $j,
                            'phase_deg' => $phase,
                            'allowedness' => $this->degFormat($orb, 3)
                        ];
                    }
                }
            }
        }
        $midpointPhases = $result['midpoint_phase'];

        $result['midpoint_phase'] = [];

        for ($i = 0; $i < 21; $i++)
        {
            if (isset($midpointPhases[$i]))
            {
                $result['midpoint_phase'][] = $midpointPhases[$i];
            }
        }

        return $result;
    }

    /**
     * 上帝手指
     * 150°-150°-60°
     * 2-2-4
     * @param array $base_data
     * @return array
     */
    protected function godFinger($base_data = [])
    {
        $ret = [];
        for ($i = 0; $i < 10; $i++)
        {
            $a = $base_data['planets'][$i];
            $deg1 = $a['deg'];
            for ($j = $i + 1; $j < 10; $j++)
            {
                $b = $base_data['planets'][$j];
                $deg2 = $b['deg'];
                $diff1_2 = abs($deg1 - $deg2); // 计算相差度数1-2
                if ($diff1_2 > 180) $diff1_2 = 360 - $diff1_2;

                if ($diff1_2 > 148 && $diff1_2 < 152)
                {
                    for ($k = 0; $k < 10; $k++)
                    {
                        $c = $base_data['planets'][$k];
                        $deg3 = $c['deg'];
                        $diff1_3 = abs($deg1 - $deg3); // 计算相差度数1-3
                        if ($diff1_3 > 180) $diff1_3 = 360 - $diff1_3;
                        $diff2_3 = abs($deg2 - $deg3); // 计算相差度数2-3
                        if ($diff2_3 > 180) $diff2_3 = 360 - $diff2_3;
                        if ($i != $k && $j != $k
                            && (($diff1_3 > 148 && $diff1_3 < 152 && $diff2_3 > 56 && $diff2_3 < 64)
                                || ($diff1_3 > 56 && $diff1_3 < 64 && $diff2_3 > 148 && $diff2_3 < 152))
                        )
                        {
                            $ret[] = [
                                [
                                    'id' => $i,
                                    'in_sign_id' => $a['in_sign_id'],
                                    'in_house_id' => $a['in_house_id'],
                                    'top' => false,
                                ],
                                [
                                    'id' => $j,
                                    'in_sign_id' => $b['in_sign_id'],
                                    'in_house_id' => $b['in_house_id'],
                                    'top' => false,
                                ],
                                [
                                    'id' => $k,
                                    'in_sign_id' => $c['in_sign_id'],
                                    'in_house_id' => $c['in_house_id'],
                                    'top' => true,
                                ],
                            ];
                        }

                    }
                }

            }
        }
        return $ret;
    }

    /**
     * 检查是否包含
     * @param string $string 如 0-2-6
     * @param array $arr 如 ['0-2-6-9','0-2-3-6']
     * @return bool
     */
    protected function checkIn($string = '', $arr = [])
    {
        if (empty($arr)) return false;

        if (in_array($string, $arr)) return true;
        // 将字符串拆分成数组
//        $string_arr = explode('-',$string);
//        foreach ($arr as $a)
//        {
//            $num = 0;
//            $arr_arr = explode('-',$a);
//            foreach ($string_arr as $s)
//            {
//                if(in_array($s,$arr_arr)) $num++;
//            }
//            // 若包含  则立即返回true
//            if(count($string_arr) == $num) return true;
//        }
        return false;
    }

    /**
     * 重新排序
     * @param string $str
     * @param array $data
     * @param string $sort_by
     * @param array $base_data
     * @return array
     */
    protected function resetSort($str = '', $data = [], $sort_by = 'deg', $base_data = [])
    {
        if ($str == '' || !is_array($data) || empty($data)) return [];
        $dataCount = count($data);
        foreach ($data as $k1 => $d1)
        {
            for ($k2 = $k1 + 1; $k2 < $dataCount; $k2++)
            {
                if ($base_data['planets'][$data[$k1]['id']][$sort_by] > $base_data['planets'][$data[$k2]['id']][$sort_by])
                {
                    $temp = $data[$k1];// 此处不能用$d1
                    $data[$k1] = $data[$k2];
                    $data[$k2] = $temp;
                }
            }
        }
        return $data;
    }

    /**
     * 行星落宫
     * @param int 1-12
     * @param array $house
     * @return int
     */
    public function inWhichHouse($longitude = 0, $house = array())
    {
        $house[13]['deg'] = $house[1]['deg'] ?? $house[1];
        $in_house = 12;
        for ($j = 1; $j <= 12; $j++)
        {
            $pl = $longitude + (1 / 36000);
            $h_now = $house[$j]['deg'] ?? $house[$j];
            $h_next = $house[$j + 1]['deg'] ?? $house[$j + 1];

            if ($j < 12 && $h_now > $h_next)
            {
                if (($pl >= $h_now && $pl < 360) || ($pl < $h_next && $pl >= 0))
                {
                    return $j;
                }
            }
            if ($j == 12 && ($h_now > $house[13]['deg']))
            {
                if (($pl >= $h_now && $pl < 360) || ($pl < $house[13]['deg'] && $pl >= 0))
                {
                    return $j;
                }
            }
            if (($pl >= $h_now) && ($pl < $h_next && ($j < 12)))
            {
                return $j;
            }
            if (($pl >= $h_now) && ($pl < $house[13]['deg']) && ($j == 12))
            {
                return $j;
            }
        }
        return $in_house;
    }

    /**
     * 计算古典七星角宫\果宫\续宫
     * @param $utdatenow
     * @param $utnow
     * @param $longitude
     * @param $latitude
     * @param $details
     * @param string $type 特殊盘名称   特殊处理
     * @return array
     */
    protected function getHouseInfo($utdatenow, $utnow, $longitude, $latitude, $details, $type = 'normal')
    {
        $ret = $details;
        $hsys1 = ($latitude <= 66.5 && $latitude >= -66.5) ? 'p' : 'b';
        $hsys2 = 'w';

        // 12/3分盘象限特殊处理 象限使用equal-asc进行计算
        if ($type === 'dodekatemorion0' || $type === 'dodekatemorion1')
        {
            $hsys1 = 'a';
        }

        $exec_str1 = $this->exec_prefix . " -b$utdatenow -ut$utnow -p0123456789 -eswe -house$longitude,$latitude,$hsys1 -fld -g, -head";
        $exec_str2 = $this->exec_prefix . " -b$utdatenow -ut$utnow -p0123456789 -eswe -house$longitude,$latitude,$hsys2 -fld -g, -head";
        exec($exec_str1, $out1);
        exec($exec_str2, $out2);
        $hcs1 = $hcs2 = [];

        for ($i = 1; $i < 13; $i++)
        {
            /**
             * 福点盘处理
             * 福点所落宫位为1宫，强制整宫制
             */
            if ($type === 'fortune')
            {
                if (!isset($hcTmp)) $hcTmp = floor($details['planets'][14]['deg'] / 30) * 30;
                $hcs1[$i]['deg'] = $hcs2[$i]['deg'] = $this->mod360($hcTmp + ($i - 1) * 30);
            } else
            {
                $hcs1[$i]['deg'] = @explode(',', $out1[$i + 9])[0] * 1;
                $hcs2[$i]['deg'] = @explode(',', $out2[$i + 9])[0] * 1;
            }
        }

        for ($i = 0; $i < 7; $i++)
        {
            $tmp1 = @explode(',', $out1[$i]);
            $tmp2 = @explode(',', $out2[$i]);

            $deg1 = $tmp1[0] * 1;
            $deg2 = $tmp2[0] * 1;

            if ($type === 'dodekatemorion0')
            {
                $deg2 = $this->dodekatemorionCacl($deg2, 0);
            } elseif ($type === 'dodekatemorion1')
            {
                $deg2 = $this->dodekatemorionCacl($deg2, 1);
            }

            $h1 = $this->inWhichHouse($deg1, $hcs1);
            $h2 = $this->inWhichHouse($deg2, $hcs2);

            $h1i = $h1 % 3;
            $h2i = $h2 % 3;

            if ($h1i === 1) $ret['influence']['p']['angular'][] = $i;
            elseif ($h1i === 2) $ret['influence']['p']['continues'][] = $i;
            elseif ($h1i === 0) $ret['influence']['p']['apoklimas'][] = $i;

            if ($h2i === 1) $ret['influence']['w']['angular'][] = $i;
            elseif ($h2i === 2) $ret['influence']['w']['continues'][] = $i;
            elseif ($h2i === 0) $ret['influence']['w']['apoklimas'][] = $i;
        }
        // 12/3分盘去除赤纬平行 由于不知道赤纬是否会受行星度数影响
        if ($type !== 'dodekatemorion0' && $type !== 'dodekatemorion1')
        {
            $ret['according'] = ['just' => [], 'reverse' => []];
            $ds = [];
            for ($i = 0; $i < 10; $i++)
            {
                $d = @explode(',', $out1[$i])[1] * 1;
                $ds[] = $d;
            }
            foreach ($ds as $k1 => $d1)
            {
                foreach ($ds as $k2 => $d2)
                {
                    if ($k1 < $k2 && abs(abs($d1) - abs($d2)) <= 1)
                    {
                        // 反纬照
                        if ($d1 * $d2 < 0)
                        {
                            $ret['according']['reverse'][] = [$k1, $k2];
                        } // 纬照
                        else
                        {
                            $ret['according']['just'][] = [$k1, $k2];
                        }
                    }
                }
            }
        }
        return $ret;
    }

    /**
     * 计算福点得分
     * @param array $details
     * @param int $year
     * @param bool $isDaily 是否为日间盘
     * @return array
     */
    protected function getFortScore($details = [], $year = 1993, $isDaily = false): array
    {
        $sign_score = 0;
        $house_score = 0;
        $phase_score = 0;
        $star_score = 0;
        // 修复本命盘关闭上升星盘无法显示的问题
        $asc = $details['planets'][ASC]['deg'] ?? $details['houses'][1]['deg'];
        $sun = $details['planets'][0]['deg'];
        $moon = $details['planets'][1]['deg'];
        $fort = $isDaily ? ($asc + $moon - $sun) : ($asc - $moon + $sun);
        if ($fort >= 360) $fort -= 360;
        elseif ($fort < 0) $fort += 360;

        $in_sign_id = InWhichSign($fort);
        $in_sign_deg = $fort - ($in_sign_id - 1) * 30;

        ###################
        // 福点位于金牛座或双鱼座(+5)
        if (in_array($in_sign_id, [2, 12], true))
        {
            $sign_score += 5;
        } // 福点在天秤、射手、狮子或巨蟹(+4)
        elseif (in_array($in_sign_id, [7, 9, 5, 4], true))
        {
            $sign_score += 4;
        } // 福点在双子(+3)
        elseif ($in_sign_id === 3)
        {
            $sign_score += 3;
        } // 福点在天蝎、摩羯或水瓶(-5)
        elseif (in_array($in_sign_id, [8, 10, 11], true))
        {
            $sign_score += 4;
        } // 福点在白羊(0)
        elseif ($in_sign_id === 1)
        {
            $sign_score += 0;
        } // 福点在处女时
        elseif ($in_sign_id === 6)
        {
            // 合金星和木星守护的界(+2)
            if ($in_sign_deg >= 17 && $in_sign_deg < 28)
            {
                $sign_score += 2;
            }
        }
        // 福点合金星和木星界(+6)
        if (
            // 白羊座
            (
                $in_sign_id === 1
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 6)
                    || ($in_sign_deg >= 6 && $in_sign_deg < 12)
                )
            )
            ||
            // 金牛座
            (
                $in_sign_id === 2
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 8)
                    || ($in_sign_deg >= 14 && $in_sign_deg < 22)
                )
            )
            ||
            // 双子座
            (
                $in_sign_id === 3
                &&
                (
                    ($in_sign_deg >= 12 && $in_sign_deg < 17)
                    || ($in_sign_deg >= 6 && $in_sign_deg < 12)
                )
            )
            ||
            // 巨蟹座
            (
                $in_sign_id === 4
                &&
                (
                    ($in_sign_deg >= 7 && $in_sign_deg < 13)
                    || ($in_sign_deg >= 19 && $in_sign_deg < 26)
                )
            )
            ||
            // 狮子座
            (
                $in_sign_id === 5
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 6)
                    || ($in_sign_deg >= 6 && $in_sign_deg < 11)
                )
            )
            ||
            // 天秤座
            (
                $in_sign_id === 7
                &&
                (
                    ($in_sign_deg >= 21 && $in_sign_deg < 28)
                    || ($in_sign_deg >= 14 && $in_sign_deg < 21)
                )
            )
            ||
            // 天蝎座
            (
                $in_sign_id === 8
                &&
                (
                    ($in_sign_deg >= 7 && $in_sign_deg < 11)
                    || ($in_sign_deg >= 19 && $in_sign_deg < 24)
                )
            )
            ||
            // 射手座
            (
                $in_sign_id === 9
                &&
                (
                    ($in_sign_deg >= 12 && $in_sign_deg < 17)
                    || ($in_sign_deg >= 0 && $in_sign_deg < 12)
                )
            )
            ||
            // 摩羯座
            (
                $in_sign_id === 10
                &&
                (
                    ($in_sign_deg >= 14 && $in_sign_deg < 22)
                    || ($in_sign_deg >= 7 && $in_sign_deg < 14)
                )
            )
            ||
            // 水瓶座
            (
                $in_sign_id === 11
                &&
                (
                    ($in_sign_deg >= 7 && $in_sign_deg < 13)
                    || ($in_sign_deg >= 13 && $in_sign_deg < 20)
                )
            )
            ||
            // 双鱼座
            (
                $in_sign_id === 12
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 12)
                    || ($in_sign_deg >= 12 && $in_sign_deg < 16)
                )
            )
        )
        {
            $sign_score += 6;
        }
        // 福点部分合土星或火星守护的界(-5)
        if (
            // 白羊座
            (
                $in_sign_id === 1
                &&
                (
                    ($in_sign_deg >= 20 && $in_sign_deg < 25)
                    || ($in_sign_deg >= 25 && $in_sign_deg < 30)
                )
            )
            ||
            // 金牛座
            (
                $in_sign_id === 2
                &&
                (
                    ($in_sign_deg >= 27 && $in_sign_deg < 30)
                    || ($in_sign_deg >= 22 && $in_sign_deg < 27)
                )
            )
            ||
            // 双子座
            (
                $in_sign_id === 3
                &&
                (
                    ($in_sign_deg >= 17 && $in_sign_deg < 24)
                    || ($in_sign_deg >= 24 && $in_sign_deg < 30)
                )
            )
            ||
            // 巨蟹座
            (
                $in_sign_id === 4
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 7)
                    || ($in_sign_deg >= 26 && $in_sign_deg < 30)
                )
            )
            ||
            // 狮子座
            (
                $in_sign_id === 5
                &&
                (
                    ($in_sign_deg >= 24 && $in_sign_deg < 30)
                    || ($in_sign_deg >= 11 && $in_sign_deg < 18)
                )
            )
            ||
            // 处女座
            (
                $in_sign_id === 6
                &&
                (
                    ($in_sign_deg >= 21 && $in_sign_deg < 28)
                    || ($in_sign_deg >= 28 && $in_sign_deg < 30)
                )
            )
            ||
            // 天秤座
            (
                $in_sign_id === 7
                &&
                (
                    ($in_sign_deg >= 28 && $in_sign_deg < 30)
                    || ($in_sign_deg >= 0 && $in_sign_deg < 6)
                )
            )
            ||
            // 天蝎座
            (
                $in_sign_id === 8
                &&
                (
                    ($in_sign_deg >= 0 && $in_sign_deg < 7)
                    || ($in_sign_deg >= 24 && $in_sign_deg < 30)
                )
            )
            ||
            // 射手座
            (
                $in_sign_id === 9
                &&
                (
                    ($in_sign_deg >= 26 && $in_sign_deg < 30)
                    || ($in_sign_deg >= 21 && $in_sign_deg < 26)
                )
            )
            ||
            // 摩羯座
            (
                $in_sign_id === 10
                &&
                (
                    ($in_sign_deg >= 26 && $in_sign_deg < 30)
                    || ($in_sign_deg >= 22 && $in_sign_deg < 26)
                )
            )
            ||
            // 水瓶座
            (
                $in_sign_id === 11
                &&
                (
                    ($in_sign_deg >= 20 && $in_sign_deg < 25)
                    || ($in_sign_deg >= 25 && $in_sign_deg < 30)
                )
            )
            ||
            // 双鱼座
            (
                $in_sign_id === 12
                &&
                (
                    ($in_sign_deg >= 19 && $in_sign_deg < 28)
                    || ($in_sign_deg >= 28 && $in_sign_deg < 30)
                )
            )
        )
        {
            $sign_score -= 5;
        }
        ###################


        $in_house_id = $this->inWhichHouse($fort, $details['houses']);
        #########################
        if ($in_house_id === 1 || $in_house_id === 10)
        {
            $house_score += 5;
        } elseif ($in_house_id === 4 || $in_house_id === 7 || $in_house_id === 11)
        {
            $house_score += 4;
        } elseif ($in_house_id === 2 || $in_house_id === 5)
        {
            $house_score += 3;
        } elseif ($in_house_id === 9)
        {
            $house_score += 2;
        } elseif ($in_house_id === 3)
        {
            ++$house_score;
        } elseif ($in_house_id === 12)
        {
            $house_score -= 5;
        } elseif ($in_house_id === 6 || $in_house_id === 8)
        {
            $house_score -= 4;
        }
        #############################

        if (abs($sun - $fort) > 270)
        {
            if ($sun > $fort) $dist = $fort + 360 - $sun;
            else $dist = $sun + 360 - $fort;
        } else
        {
            $dist = abs($sun - $fort);
        }
        $burn = 0;// 是否灼伤
        if ($dist > 8.5 && $dist <= 15) $burn = 1; // 在日光下 15
        if ($dist > 17 / 60 && $dist <= 8.5) $burn = 2; // 灼伤 8.5
        #########################################
        foreach ($details['planets'] as $i => $p)
        {
            if (in_array($i, [3, 4, 5, 6, 12], true))
            {
                $p_deg = $p['deg'];

                $da = abs($p_deg - $fort);
                if ($da > 180) $da = 360 - $da;

                $phases = [0, 60, 90, 120, 180];

                foreach ($phases as $ps)
                {
                    if ($da <= ($ps + $this->options['asps_orb'][$ps]) && $da >= ($ps - $this->options['asps_orb'][$ps]))
                    {
                        if ($i === 3 || $i === 5)
                        {
                            if ($ps === 0) $phase_score += 5;
                            elseif ($ps === 120) $phase_score += 4;
                            elseif ($ps === 60) $phase_score += 3;
                        }
                        if ($i === 12)
                        {
                            if ($ps === 0) $phase_score += 3;
                            elseif ($ps === 180) $phase_score -= 3;
                        }

                        if ($i === 4 || $i === 6)
                        {
                            if ($ps === 180) $phase_score -= 4;
                            elseif ($ps === 0) $phase_score -= 6;
                            elseif ($ps === 60 || $ps === 120) $phase_score -= 2;
                        }
                    }
                }
            }
        }
        if ($burn !== 1 && $burn !== 2) $phase_score += 5;
        elseif ($burn === 1) $phase_score -= 5;
        #########################################

        ###################################################################
        $diff = ($year * 1 - 2000) * 0.83 / 60;
        // 计算恒星 每一百年移动83′ 每年0.83分
        foreach ($this->getConfigFromFile('star') as $s)
        {
            $star = $s[0] + $diff;
            // 合恒星
            if (abs($fort - $star) <= 1)
            {
                // 吉凶状态  凶 平 吉 大吉
                if ($s[1] === '轩辕十四') $star_score += 6;
                elseif ($s[1] === '角宿一') $star_score += 5;
                elseif ($s[1] === '大陵五') $star_score -= 6;
                elseif ($s[6] === '吉' || $s[6] === '大吉') $star_score += 4;
                elseif ($s[6] === '凶') $star_score -= 4;

            }
            $fortStarAbs = abs($fort - $star);
            // 刑恒星
            if ($fortStarAbs <= 91 && $fortStarAbs >= 89)
            {
                if ($s[6] === '凶') $star_score -= 3;
            } // 冲恒星
            elseif ($fortStarAbs <= 181 && $fortStarAbs >= 179)
            {
                if ($s[6] === '凶') $star_score -= 4;
            }
        }
        ###################################################################
        $total = $sign_score + $house_score + $phase_score + $star_score;
        $ret = ['ecliptic' => $sign_score, 'house' => $house_score, 'phase' => $phase_score, 'star' => $star_score, 'total' => $total];

        return $ret;
    }

    /**
     * 大限、主限运势星
     * @param null $birthtime
     * @param int $years_alive
     * @param bool $isDaily 是否为日生盘
     * @return array
     */
    protected function getTheMainSubLuck($birthtime = null, $years_alive = 0, $isDaily = false): array
    {
        $astroConfig = $this->getConfigFromFile();
        // 日间盘
        if ($isDaily === true) $firdaria_main = $astroConfig['firdaria_main_day'];
        // 夜间盘
        else $firdaria_main = $astroConfig['firdaria_main_night_' . $this->options['firdaria']];
        $years_alive_or = $years_alive;
        $years_alive_whole = floor($years_alive / 75) * 75;
        // 大于75岁 从头开始
        $years_alive -= $years_alive_whole;
        $years = $years_temp = 0;
        $time_main = $time_sub = $birthtime;
        $main_luck = $sub_luck = null;

        $advanceTime = $this->recode1['timezone'] * 3600;

        $ret = [];
        foreach ($firdaria_main as $i => $f)
        {
            $y = $astroConfig['firdaria_planet_years'][$f];
            // 以当前大限主管星为起始星(小限)
            $sub_planets = $this->getTheSubPlanets($f);
            $pro_add_sub = count($sub_planets) === 1 ? $y : $y / 7;//大限平分七份为小限时间  南北交时为全部
            $pro_add_sub_time = $pro_add_sub * 365.2422 * 24 * 3600;

            $sub_details = [];
            foreach ($sub_planets as $j => $s)
            {
                $sub_details[] = [
                    'id' => $s,
                    'cross' => $pro_add_sub,
                    'year_min' => $years_temp + $years_alive_whole,
                    'year_max' => $years_temp + $pro_add_sub + $years_alive_whole,
                    'start' => date('Y年m月d日', strtotime('+' . $years_alive_whole . 'year', $time_sub + $advanceTime)),
                    'end' => date('Y年m月d日', strtotime('+' . $years_alive_whole . 'year', $time_sub + $pro_add_sub_time + $advanceTime)),
                ];
                $years_temp += $pro_add_sub;
                $time_sub += $pro_add_sub_time;

                if ($years_alive <= $years_temp && $sub_luck === null) $sub_luck = $s;
            }
            $ret['details'][] = [
                'main' => [
                    'id' => $f,
                    'cross' => $y,
                    'year_min' => $years + $years_alive_whole,
                    'year_max' => $years + $y + $years_alive_whole,
                    'start' => date('Y年m月d日', strtotime('+' . $years_alive_whole . 'year', $time_main + $advanceTime)),
                    'end' => date('Y年m月d日', strtotime('+' . ($y + $years_alive_whole) . ' year', $time_main + $advanceTime)),
                ],
                'sub' => $sub_details,
            ];
            $years += $y;
            $time_main = strtotime("+$y year", $time_main);

            if ($years_alive <= $years && $main_luck === null) $main_luck = $f;
        }
        $ret['main_luck'] = $main_luck;
        $ret['sub_luck'] = $sub_luck;
        $ret['years_alive'] = $years_alive_or;

        return $ret;
    }

    /**
     * 获取当前小限星 数组
     * @param int $main
     * @return array
     */
    protected function getTheSubPlanets(int $main): array
    {
        // 以当前大限主管星为起始星(小限)
        $sub_planets = $this->getConfigFromFile('firdaria_sub');

        if ($main === 16 || $main === 12)
        {
            return [$main];
        }

        $temp = [];
        $start = false;
        $num = 0;
        foreach ($sub_planets as $s)
        {
            if ($s === $main || $start === true)
            {
                $temp[] = $s;
                $start = true;
                $num++;
                if ($num === 7)
                {
                    break;
                }
            }
        }
        return $temp;
    }

    /**
     * 计算两个时间戳相差月份数（日历自然月）
     * @param null integer $time1 开始时间戳
     * @param null integer $time2 结束时间戳
     * @return int 相差月份数
     */
    protected function getTheMonthAgo($time1 = null, $time2 = null): int
    {
        if ($time2 < $time1)
        {
//            throw new ApiException('当前选择时间早于出生时间');
            $this->error = '当前选择时间早于出生时间';
            return false;
        }
        [$year1, $month1, $day1] = explode(',', date('Y,m,d', $time1));
        [$year2, $month2, $day2] = explode(',', date('Y,m,d', $time2));

        if ($day2 < $day1)
        {
            $month2--;
        }
        if ($month2 < $month1)
        {
            $month2 += 12;
            $year2--;
        }
        return $month2 - $month1 + ($year2 - $year1) * 12;
    }

    /**
     * 获取行星星历数据
     * @param string $p 0123456789DH
     * @param null $timeinfo 时间数据
     * @return mixed
     */
    public function getPlanetOriginData($p = '0', $timeinfo = null)
    {
        $timeinfo = $timeinfo ?? $this->recode1;

        $timestamp = $this->dealTime($timeinfo);
        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);

        $exec_str = $this->exec_prefix . " -b{$utdatenow} -ut{$utnow} -p{$p} -eswe -fl -g, -head";

        exec($exec_str, $out);

        return $out;
    }

    /**
     * 获取今日天象 行星运行状态
     * @param string $p
     * @param string $f
     * @return array
     */
    public function getPlanetStateData($p = '0123456', $f = 'ls')
    {
        $tips = [];

        $options = $this->advance;

        $exec_str = $this->exec_prefix . " -b{$options['ut_date']} -ut{$options['ut_time']} -p{$p} -eswe -f{$f} -g, -head";

        exec($exec_str, $out);

        if (empty($out) || !is_countable($out) || count($out) < strlen($p))
        {
            $this->error = '行星数据获取失败，请检查';
            return $tips;
        }

        $astrologConfigs = config('astrolog');
        $averageSpeeds = $astrologConfigs['speed'];
        $planetsNames = $astrologConfigs['planets_name'];
        $signNames = $astrologConfigs['sign_name'];

        $tip = '';
        foreach ($out as $key => $line)
        {
            if ($key <= 6)
            {
                $row = explode(',', $line);
                $deg = @(float)$row[0] * 1;
                $in_sign_id = InWhichSign($deg);
                $speed = @(float)$row[1];

                $pName = explode('|', $planetsNames[$key])[3];
                $sName = explode('|', $signNames[$in_sign_id])[3];
                //太阳运行在XX座、 月亮运行在XX座、 X星运行在XX座
                //X星在XX座逆行、 X星在XX座停滞
                if ($key % 2 === 0)
                {
                    $tip = $pName;
                } else
                {
                    $tip .= ' - ' . $pName;
                }

                if ($averageSpeeds[$key] !== 0 && abs($speed) <= $averageSpeeds[$key] / 5)
                {
                    $tip .= '在' . $sName . '停滞';
                } elseif ($speed < 0)
                {
                    $tip .= '在' . $sName . '逆行';
                } else
                {
                    $tip .= '运行在' . $sName;
                }
                if ($key % 2 === 1 || $key === 6)
                {
                    $tips[] = $tip;
                }
            }
        }
        return $tips;
    }

    /**
     * 获取星历数据
     * @param array $options
     * @return mixed
     */
    protected function execData($options = [])
    {
        $exec_str = $this->exec_prefix . " -b{$options['utdatenow']} -ut{$options['utnow']} -p0123456789DAmHt -eswe -house{$options['longitude']},{$options['latitude']},{$options['h_sys']} -fldsa -g, -head";

        exec($exec_str, $out);

        if (empty($out) || !is_countable($out) || count($out) < 27)
        {
            unset($out);
            $exec_str = $this->exec_prefix . " -b{$options['utdatenow']} -ut{$options['utnow']} -p0123456789DAmHt -eswe -house{$options['longitude']},{$options['latitude']},b -fldsa -g, -head";

            exec($exec_str, $out);
        }

        return $out;
    }

    /**
     * 切换星盘配置
     * @param string $chart 需要切换到的星盘
     */
    protected function switchConfiguration($chart = 'now'): void
    {
        try
        {
            if (isset($this->options['setting'][$chart]['planet']) && !empty($this->options['setting'][$chart]['planet']))
            {
                $this->options['planets_display'] = '';
                $this->options['planets_orb'] = [];
                foreach ($this->options['setting'][$chart]['planet'] as $pl_set)
                {
                    $this->options['planets_display'] .= $pl_set[0];
                    $this->options['planets_orb'][] = $pl_set[1];
                }
            } else
            {
                $this->options['planets_orb'] = $this->options['setting'][$chart]['planet_orb_all'];
                $this->options['planets_display'] = $this->options['setting'][$chart]['planets_display'];
            }

            if (isset($this->options['setting'][$chart]['phase']) && !empty($this->options['setting'][$chart]['phase']))
            {
                $this->options['asps_display'] = [];
                $this->options['asps_orb'] = [];
                foreach ($this->options['setting'][$chart]['phase'] as $asp => $ph_set)
                {
                    if ($ph_set[0] === 1)
                    {
                        $this->options['asps_display'][] = $asp;
                    }
                    $this->options['asps_orb'][$asp] = $ph_set[1];
                }
            } else
            {
                $this->options['asps_display'] = $this->options['setting'][$chart]['asps_display'];
                $this->options['asps_orb'] = $this->options['setting'][$chart]['asp_orb_all'];
            }

            $this->options['h_sys'] = $this->options['setting'][$chart]['h_sys'];
            // 设置法达配置
            if (isset($this->options['setting'][$chart]['firdaria']))
            {
                $this->options['firdaria'] = $this->options['setting'][$chart]['firdaria'];
            }
            // 设置界主星配置
            if (isset($this->options['setting'][$chart]['bound_type']))
            {
                $this->options['bound_type'] = $this->options['setting'][$chart]['bound_type'];
            }
            // 设置十度配置
            if (isset($this->options['setting'][$chart]['decanates']))
            {
                $this->options['decanates'] = $this->options['setting'][$chart]['decanates'];
            }
            // 设置小限方向
            if (isset($this->options['setting'][$chart]['profection_push_direction']))
            {
                $this->options['profection_push_direction'] = $this->options['setting'][$chart]['profection_push_direction'];
            }
            // 设置希腊点的配置
            if (isset($this->options['setting'][$chart]['arabic']))
            {
                $this->options['arabics'] = $this->options['setting'][$chart]['arabic'];
            }
            // 设置返照盘使用的推运地点数据 0 现居地 ｜｜ 1 出生地
            if (isset($this->options['setting'][$chart]['location_use']))
            {
                $this->options['location_use'] = (int)$this->options['setting'][$chart]['location_use'];
            }
            // 设置行星中点配置 默认为近中点 0 || 远中点 1 || 不考虑 2
            if (isset($this->options['setting'][$chart]['mid_type']))
            {
                $this->options['mid_type'] = (int)$this->options['setting'][$chart]['mid_type'];
            }
        }
        catch (Exception $e)
        {
            $this->error = 'switchConfiguration:' . $e->getMessage();
        }
    }

    /**
     * 获取天象盘数据
     * @return array
     */
    protected function getNowData(): array
    {
        $options = [
            'utdatenow' => $this->advance['ut_date'],
            'utnow' => $this->advance['ut_time'],
            'longitude' => $this->advance['longitude'],
            'latitude' => $this->advance['latitude'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->advance['year']);

        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        $details = $this->getStructure($details);

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $syzygy = $this->getSyzygyData($this->advance);

            $details['arabics'][8]['deg'] = $syzygy;
            $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
            $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);

            $details['characteristic'] = $this->receptOrMutualRecept($details['planets']);

            if ($this->options['version'] > 1)
            {
                // 光线围攻
                $lightSiege = $this->lightSiege($details['planets']);
                if (!empty($lightSiege))
                {
                    $details['characteristic'][9] = $lightSiege;
                }

                $between = $this->getBetweenHousePlanet($details['planets'], $details['houses']);
                if (!empty($between['between_house']))
                {
                    // 夹宫
                    $details['characteristic'][10] = $between['between_house'];
                }
                if (!empty($between['between_planet']))
                {
                    // 夹星
                    $details['characteristic'][11] = $between['between_planet'];
                }

                $gb = $this->getBetweenPlanetGoodOrBad($details['planets']);
                if (!empty($gb['bad']))
                {
                    // 夹制
                    $details['characteristic'][12] = $gb['bad'];
                }
                if (!empty($gb['good']))
                {
                    // 夹辅
                    $details['characteristic'][13] = $gb['good'];
                }
            }

            // 福点分数
            $details['fortune'] = $this->getFortScore($details, $this->advance['year'], $original_data['day_chart']);

            $details = $this->getHouseInfo($this->advance['ut_date'], $this->advance['ut_time'], $this->advance['longitude'], $this->advance['latitude'], $details);
            // 指定输出为object  防止类型改变
            $details['characteristic'] = (object)$details['characteristic'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details['planets'] = (object)$details['planets'];
        }

        return $details;
    }

    /**
     * 获取本命盘数据
     * @return array
     */
    protected function getNatalData(): array
    {
        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->recode1['year']);

        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $syzygy = $this->getSyzygyData($this->recode1);

            $details['arabics'][8]['deg'] = $syzygy;
            $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
            $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);

            $details = $this->getStructure($details);

            $details['characteristic'] = $this->receptOrMutualRecept($details['planets']);

            if ($this->options['version'] > 1)
            {
                // 光线围攻
                $lightSiege = $this->lightSiege($details['planets']);
                if (!empty($lightSiege))
                {
                    $details['characteristic'][9] = $lightSiege;
                }

                $between = $this->getBetweenHousePlanet($details['planets'], $details['houses']);
                if (!empty($between['between_house']))
                {
                    // 夹宫
                    $details['characteristic'][10] = $between['between_house'];
                }
                if (!empty($between['between_planet']))
                {
                    // 夹星
                    $details['characteristic'][11] = $between['between_planet'];
                }

                $gb = $this->getBetweenPlanetGoodOrBad($details['planets']);
                if (!empty($gb['bad']))
                {
                    // 夹制
                    $details['characteristic'][12] = $gb['bad'];
                }
                if (!empty($gb['good']))
                {
                    // 夹辅
                    $details['characteristic'][13] = $gb['good'];
                }
            }

            // 福点分数
            $details['fortune'] = $this->getFortScore($details, $this->recode1['year'], $original_data['day_chart']);


            $details = $this->getHouseInfo($this->recode1['ut_date'], $this->recode1['ut_time'], $this->recode1['birth_lng'], $this->recode1['birth_lat'], $details);
            // 指定输出为object  防止类型改变
            $details['characteristic'] = (object)$details['characteristic'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details['planets'] = (object)$details['planets'];
        }

        return $details;
    }

    /**
     * 获取行运盘数据
     * @return array
     */
    protected function getTransitsData(): array
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $this->advance['ut_date'],
            'utnow' => $this->advance['ut_time'],
            // 行运盘使用本命的经纬度
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
//            'longitude' => $this->advance['longitude'],
//            'latitude' => $this->advance['latitude'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $original_data1 = $this->getOriginalData($out1);
        $original_data2 = $this->getOriginalData($out2);

        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);

        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);

        $phase1 = $this->planetPkPlanet($original_data1, $original_data2, false, 1);

        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = null;
        }
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);

        $phase2 = $this->planetPkPlanet($original_data2, $original_data1, false, 2);

        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            /**
             * 行运盘 朔望点不开启时，不进行计算
             */
            if (isset($this->options['arabics']) && isset($this->options['arabics'][8][0]) && $this->options['arabics'][8][0] === 1)
            {
                $syzygy1 = $this->getSyzygyData($this->recode1);

                $details1['arabics'][8]['deg'] = $syzygy1;
                $details1['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy1);
                $details1['arabics'][8]['in_sign_id'] = InWhichSign($syzygy1);

                $syzygy2 = $this->getSyzygyData($this->advance);

                $details2['arabics'][8]['deg'] = $syzygy2;
                $details2['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy2);
                $details2['arabics'][8]['in_sign_id'] = InWhichSign($syzygy2);
            }

            // 指定输出为object  防止所有行星全开时 类型改变
            $details1['planets'] = (object)$details1['planets'];
            $details2['planets'] = (object)$details2['planets'];
        }

        return [$details1, $details2];
    }

    /**
     * 获取三次限数据
     * @param float $coef 默认三限参数27.321661     次限参数365.2422
     * @return array
     */
    protected function getThirdprogressedData($coef = 27.321661): array
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = $this->recode1['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $prog_time_to_add = $days_alive / $coef; // 即本命后第几天

        $time_before_JD = $birth_JD + floor($prog_time_to_add);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro = $prog_time_to_add - floor($prog_time_to_add);

        $date_before = strtotime(jdtogregorian($time_before_JD));
        $date_after = strtotime('+1 day', $date_before);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before);
        $utnow1 = $this->recode1['ut_time'];

        $utdatenow2 = strftime('%d.%m.%Y', $date_after);
        $utnow2 = $this->recode1['ut_time'];

        $options1 = ['utdatenow' => $utdatenow1, 'utnow' => $utnow1, 'longitude' => $this->recode1['birth_lng'], 'latitude' => $this->recode1['birth_lat'], 'h_sys' => $this->options['h_sys']];
        $options2 = ['utdatenow' => $utdatenow2, 'utnow' => $utnow2, 'longitude' => $this->recode1['birth_lng'], 'latitude' => $this->recode1['birth_lat'], 'h_sys' => $this->options['h_sys']];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $calOut = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro);

        $original_data = $this->getOriginalData($calOut);
        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        // 绘制星盘时，不需要结构参数
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];
            $details['planets'] = (object)$details['planets'];
            $details['time1'] = date('Y-m-d H:i:s', $date_before);
        } else
        {
            $details = $this->getStructure($details, true);
        }

        return $details;
    }

    /**
     * 获取三次限VS本命盘的数据
     * @param float $coef
     * @return array
     */
    protected function getThirdprogressedVsNatalData($coef = 27.321661): array
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = $this->recode1['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $prog_time_to_add = $days_alive / $coef; // 即本命后第几天

        $time_before_JD = $birth_JD + floor($prog_time_to_add);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro = $prog_time_to_add - floor($prog_time_to_add);

        $date_before = strtotime(jdtogregorian($time_before_JD));
        $date_after = strtotime('+1 day', $date_before);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before);
        $utnow1 = $this->recode1['ut_time'];

        $utdatenow2 = strftime('%d.%m.%Y', $date_after);
        $utnow2 = $this->recode1['ut_time'];

        $options1 = [
            'utdatenow' => $utdatenow1,
            'utnow' => $utnow1,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $utdatenow2,
            'utnow' => $utnow2,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options3 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);
        $out_natal = $this->execData($options3);

        $calOut = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro);

        $original_data1 = $this->getOriginalData($out_natal);
        $original_data2 = $this->getOriginalData($calOut);
        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);
        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2);
        $phase2 = $this->planetPkPlanet($original_data2, $original_data1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = null;
        }
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            $details1['planets'] = (object)$details1['planets'];// 指定输出为object  防止所有行星全开时 类型改变
            $details2['planets'] = (object)$details2['planets'];// 指定输出为object  防止所有行星全开时 类型改变

            $details['time1'] = date('Y-m-d H:i:s', $date_before);
        }

        return [$details1, $details2];
    }

    /**
     * 获取太阳弧盘数据
     * @return array
     */
    protected function getSolarData(): array
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);
        // 经过与A32对比，需要减去0.5，否则度数不一样（但是不知道为啥）
        $birth_JD = $this->recode1['ut_jd'] - 0.5;
        $start_JD = $this->advance['ut_jd'] - 0.5;

        $days_alive = $start_JD - $birth_JD; // 总天数
        $prog_time_to_add = $days_alive / 365.2422;// 365.2422  365.2421990  365.25

        $jd_to_use = $birth_JD + $prog_time_to_add;

        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);

        $exec_str2 = $this->exec_prefix . " -bj{$jd_to_use} -ut -p0 -eswe -fl -g, -head";
        exec($exec_str2, $out2);
        $original_data1 = $this->getOriginalData($out1);

        $this->arrayRemove($original_data1);

        $p_sun = $out2[0];
        $original_data2 = $this->getTheLongitudeBySolarArc($p_sun, $original_data1);

        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2, false, 1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = null;
        }

        $phase2 = $this->planetPkPlanet($original_data2, $original_data1, false, 2);
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            $details1['planets'] = (object)$details1['planets'];// 指定输出为object  防止所有行星全开时 类型改变
            $details2['planets'] = (object)$details2['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return [$details1, $details2];
    }

    /**
     * 获取太阳返照盘数据
     * @return array
     */
    protected function getSolarReturnData(): array
    {
        $now_before = $this->calculatePlanetReturnTime(0, $this->recode1, $this->advance);

        if ($this->options['location_use'] === 0)
        {
            [$longitude, $latitude] = $this->LivePlaceToLngLat($this->recode1['birth_lng'], $this->recode1['birth_lat']);
        } else
        {
            [$longitude, $latitude] = [$this->recode1['birth_lng'], $this->recode1['birth_lat']];
        }

        $utdatenow_test = strftime('%d.%m.%Y', $now_before);
        $utnow_test = strftime('%H:%M:%S', $now_before);

        $options = ['utdatenow' => $utdatenow_test, 'utnow' => $utnow_test, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        $details['return_time'] = date('Y-m-d H:i', $now_before + $this->recode1['timezone'] * 3600);

        return $details;
    }

    /**
     * 获取太阳返照双盘数据
     * @return array
     */
    protected function getSolarReturnVsNatalData(): array
    {
        $now_before = $this->calculatePlanetReturnTime(0, $this->recode1, $this->advance);

        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);

        if ($this->options['location_use'] === 0)
        {
            [$longitude, $latitude] = $this->LivePlaceToLngLat($this->recode1['birth_lng'], $this->recode1['birth_lat']);
        } else
        {
            [$longitude, $latitude] = [$this->recode1['birth_lng'], $this->recode1['birth_lat']];
        }

        $utdatenow_test = strftime('%d.%m.%Y', $now_before);
        $utnow_test = strftime('%H:%M:%S', $now_before);

        $options = ['utdatenow' => $utdatenow_test, 'utnow' => $utnow_test, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out = $this->execData($options);

        $original_data1 = $this->getOriginalData($out1);
        $original_data2 = $this->getOriginalData($out);
        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);
        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2);
        $phase2 = $this->planetPkPlanet($original_data2, $original_data1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = null;
        }
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            $details1['planets'] = (object)$details1['planets'];// 指定输出为object  防止所有行星全开时 类型改变
            $details2['planets'] = (object)$details2['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        $details1['return_time'] = $details2['return_time'] = date('Y-m-d H:i', $now_before + $this->recode1['timezone'] * 3600);

        return [$details1, $details2];
    }

    /**
     * 获取月亮返照盘数据
     * @return array
     */
    protected function getLunarReturnData(): array
    {
        $now_before = $this->calculatePlanetReturnTime(1, $this->recode1, $this->advance);

        if ($this->options['location_use'] === 0)
        {
            [$longitude, $latitude] = $this->LivePlaceToLngLat($this->recode1['birth_lng'], $this->recode1['birth_lat']);
        } else
        {
            [$longitude, $latitude] = [$this->recode1['birth_lng'], $this->recode1['birth_lat']];
        }

        $utdatenow_test = strftime('%d.%m.%Y', $now_before);
        $utnow_test = strftime('%H:%M:%S', $now_before);

        $options = [
            'utdatenow' => $utdatenow_test,
            'utnow' => $utnow_test,
            'longitude' => $longitude,
            'latitude' => $latitude,
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        $details['return_time'] = date('Y-m-d H:i', $now_before + $this->recode1['timezone'] * 3600);

        return $details;
    }

    /**
     * 获取月亮返照双盘数据
     */
    protected function getLunarReturnVsNatalData(): array
    {
        $now_before = $this->calculatePlanetReturnTime(1, $this->recode1, $this->advance);

        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);

        if ($this->options['location_use'] === 0)
        {
            [$longitude, $latitude] = $this->LivePlaceToLngLat($this->recode1['birth_lng'], $this->recode1['birth_lat']);
        } else
        {
            [$longitude, $latitude] = [$this->recode1['birth_lng'], $this->recode1['birth_lat']];
        }

        $utdatenow_test = strftime('%d.%m.%Y', $now_before);
        $utnow_test = strftime('%H:%M:%S', $now_before);

        $options = ['utdatenow' => $utdatenow_test, 'utnow' => $utnow_test, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out = $this->execData($options);

        $original_data1 = $this->getOriginalData($out1);
        $original_data2 = $this->getOriginalData($out);
        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);
        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2);
        $phase2 = $this->planetPkPlanet($original_data2, $original_data1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = null;
        }
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            $details1['planets'] = (object)$details1['planets'];// 指定输出为object  防止所有行星全开时 类型改变
            $details2['planets'] = (object)$details2['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        $details1['return_time'] = $details2['return_time'] = date('Y-m-d H:i', $now_before + $this->recode1['timezone'] * 3600);

        return [$details1, $details2];
    }

    /**
     * 获取法达盘数据
     */
    protected function getFirdariaData(): array
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = $this->recode1['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $years_alive = $days_alive / 365.2422;// 365.2422  365.2421990  365.25

        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }
        // 大运、小运
        $main_sub_luck = $this->getTheMainSubLuck($this->recode1['ut_timestamp'], $years_alive, $original_data['day_chart']);
        $details['firdaria'] = $main_sub_luck;

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $syzygy = $this->getSyzygyData($this->recode1);

            $details['arabics'][8]['deg'] = $syzygy;
            $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
            $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取小限盘数据
     * 小限法计算原理
     * 小限法是直接于命盘找出值年宫位，12年一循环。
     * 12年一个轮回，一年走一宫（流年）
     * 12个月一个轮回，一个月走一宫（流月）
     * 出生时0岁走1宫，满实足1岁时走2宫，x岁时走(x mod 12) + 1宫
     * 如:12岁，12模12余0走1宫，31岁则31模12余7走8宫
     * 31岁零6个月时走主限8宫，副限7宫
     * 起法是以ASC命度0度起始的第1宫当成0岁，第2宫为1岁（从1-12宫逐宫往后推移），即： 第1宫为0岁、第2宫为0~1岁、第3宫为1~2岁…….第12宫为11~12岁，以此循环12个宫位为一周。再次推至第1宫时则为12~13岁、第2宫为12~13岁... …逐宫往后推移。
     * 小限公式：
     * 当A的年龄N＜12岁时，1-12岁依次为第1—12宫，且该宫头所落星座的掌管行星为该值年小限。
     * 当A的年龄N ≥12岁时，N/12=X余Y，该值年小限为第X宫；当结果有余数时，只取X整数。
     * 注意：过宫时间应以实岁计算，如某人生于1981年5月6日，那麽他25岁的小限，必须在2006年5月6日过宫，25除12余1，也就是以第2宫为2006年5月6日至2007年5月6日一整年小限过运宫位。
     * @return array
     */
    protected function getProfectionData(): array
    {
        // 检测时间 错误已存储到$this->error中
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = $this->recode1['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $years_alive = $days_alive / 365.2422;// 365.2422  365.2421990  365.25
        $months_alive = $this->getTheMonthAgo($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }
        // 计算小限值年宫位
        $profection_year = $years_alive % 12 + 1;
        $profection_month = $months_alive % 12 + 1;
        $years_use = floor($years_alive) - ($profection_year - 1);
        // 顺时针
        if ($this->options['profection_push_direction'] === 1)
        {
            $profection_month = $profection_year - $profection_month;
            $profection_month = $profection_month <= 0 ? 12 + $profection_month : $profection_month;
        }// 逆时针
        else
        {
            $profection_month = $profection_year + $profection_month - 1;
            $profection_month = $profection_month > 12 ? $profection_month - 12 : $profection_month;
        }
        // 1宫起始年份与出生年份的差值：12年一轮回，用于计算1宫起始年份
        $startYearNum = (int)($years_alive / 12) * 12;
        $startYearMonthTime = strtotime("+{$startYearNum} year", $this->recode1['ut_timestamp']);
        // 1宫起始年份 时间转化为用户出生时区时间
        $startYearMonthTime += ($this->recode1['timezone'] + $this->recode1['is_summer']) * 3600;
        // 当前值年年份
        $yearNowTime = strtotime('+' . ($profection_year - 1) . ' year', $startYearMonthTime);

        for ($i = 1; $i < 13; $i++)
        {
            $end_year = strtotime("+{$i} year", $startYearMonthTime);
            $end_month = strtotime("+{$i} month", $yearNowTime);
            // 顺时针
            if ($this->options['profection_push_direction'] === 1)
            {
                $key = $profection_year - $i;

                $key = $key <= 0 ? 12 + $key : $key;
            } else
            {
                $key = $profection_year + $i - 1;

                $key = $key > 12 ? $key - 12 : $key;
            }

            $details['profection']['details'][$i]['start_year'] = date('Y年m月d日', strtotime('-1 year', $end_year));
            $details['profection']['details'][$i]['end_year'] = date('Y年m月d日', $end_year);
            $details['profection']['details'][$i]['years_old_start'] = $years_use;
            $details['profection']['details'][$i]['years_old_end'] = $years_use + 0.99;
            $details['profection']['details'][$key]['start_month'] = date('Y年m月d日', strtotime('-1 month', $end_month));
            $details['profection']['details'][$key]['end_month'] = date('Y年m月d日', $end_month);

            $years_use++;
        }

        $details['profection']['year_house'] = $profection_year;
        $details['profection']['month_house'] = $profection_month;

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];
            $syzygy = $this->getSyzygyData($this->recode1);

            $details['arabics'][8]['deg'] = $syzygy;
            $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
            $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取比较盘数据
     */
    protected function getSynastryData(): array
    {
        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $this->recode2['ut_date'],
            'utnow' => $this->recode2['ut_time'],
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $original_data1 = $this->getOriginalData($out1);
        $original_data2 = $this->getOriginalData($out2);
        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);
        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2);
        $phase2 = $this->planetPkPlanet($original_data2, $original_data1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = NULL;
        }
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = NULL;
        }

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $syzygy1 = $this->getSyzygyData($this->recode1);

            $details1['arabics'][8]['deg'] = $syzygy1;
            $details1['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy1);
            $details1['arabics'][8]['in_sign_id'] = InWhichSign($syzygy1);

            $syzygy2 = $this->getSyzygyData($this->recode2);

            $details2['arabics'][8]['deg'] = $syzygy2;
            $details2['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy2);
            $details2['arabics'][8]['in_sign_id'] = InWhichSign($syzygy2);

            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details1['planets'] = (object)$details1['planets'];
            $details2['planets'] = (object)$details2['planets'];
        } else
        {
            $details1 = $this->getStructure($details1);
            $details2 = $this->getStructure($details2);
        }

        return [$details1, $details2];
    }

    /**
     * 获取组合中点盘数据
     */
    protected function getCompositeData(): array
    {
        $options1 = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $this->recode2['ut_date'],
            'utnow' => $this->recode2['ut_time'],
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $original_data1 = $this->getOriginalData($out1);
        $original_data2 = $this->getOriginalData($out2);
        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);

        $original_data = $this->getTheCompoisteCenter($original_data1, $original_data2);

        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }
        return $details;
    }

    /**
     * 获取组合三次限盘数据
     * 原理：两个三次限盘的组合中点盘
     * @param float $coef
     * @return array
     */
    protected function getCompositeThirdprogressedData($coef = 27.321661): array
    {
        $birth_JD1 = $this->recode1['ut_jd'];
        $birth_JD2 = $this->recode2['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive1 = $start_JD - $birth_JD1; // 总天数
        $days_alive2 = $start_JD - $birth_JD2; // 总天数
        $prog_time_to_add1 = $days_alive1 / $coef; // 多少月27.321661     27.3215865
        $prog_time_to_add2 = $days_alive2 / $coef; // 多少月27.321661     27.3215865

        $time_before_JD1 = $birth_JD1 + floor($prog_time_to_add1);
        $time_before_JD2 = $birth_JD2 + floor($prog_time_to_add2);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro1 = $prog_time_to_add1 - floor($prog_time_to_add1);
        $time_change_pro2 = $prog_time_to_add2 - floor($prog_time_to_add2);

        $date_before1 = strtotime(jdtogregorian($time_before_JD1));
        $date_after1 = strtotime('+1 day', $date_before1);

        $date_before2 = strtotime(jdtogregorian($time_before_JD2));
        $date_after2 = strtotime('+1 day', $date_before2);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before1);
        $utnow1 = $this->recode1['ut_time'];

        $utdatenow2 = strftime('%d.%m.%Y', $date_after1);
        $utnow2 = $this->recode1['ut_time'];

        $utdatenow3 = strftime('%d.%m.%Y', $date_before2);
        $utnow3 = $this->recode2['ut_time'];

        $utdatenow4 = strftime('%d.%m.%Y', $date_after2);
        $utnow4 = $this->recode2['ut_time'];

        $options1 = [
            'utdatenow' => $utdatenow1,
            'utnow' => $utnow1,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $utdatenow2,
            'utnow' => $utnow2,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options3 = [
            'utdatenow' => $utdatenow3,
            'utnow' => $utnow3,
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options4 = [
            'utdatenow' => $utdatenow4,
            'utnow' => $utnow4,
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);
        $out3 = $this->execData($options3);
        $out4 = $this->execData($options4);

        $calOut1 = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro1);
        $calOut2 = $this->getProgressionThirdprogressed($out3, $out4, $time_change_pro2);


        $original_data1 = $this->getOriginalData($calOut1);
        $original_data2 = $this->getOriginalData($calOut2);

        $original_data = $this->getTheCompoisteCenter($original_data1, $original_data2);

        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取比较三次限盘数据
     * 原理：两个三次限盘的比较盘
     * @param float $coef
     * @return array
     */
    protected function getSynastryThirdprogressedData($coef = 27.321661): array
    {
        $birth_JD1 = $this->recode1['ut_jd'];
        $birth_JD2 = $this->recode2['ut_jd'];
        $start_JD = $this->advance['ut_jd'];

        $days_alive1 = $start_JD - $birth_JD1; // 总天数
        $days_alive2 = $start_JD - $birth_JD2; // 总天数
        $prog_time_to_add1 = $days_alive1 / $coef; // 多少月27.321661     27.3215865
        $prog_time_to_add2 = $days_alive2 / $coef; // 多少月27.321661     27.3215865

        $time_before_JD1 = $birth_JD1 + floor($prog_time_to_add1);
        $time_before_JD2 = $birth_JD2 + floor($prog_time_to_add2);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro1 = $prog_time_to_add1 - floor($prog_time_to_add1);
        $time_change_pro2 = $prog_time_to_add2 - floor($prog_time_to_add2);

        $date_before1 = strtotime(jdtogregorian($time_before_JD1));
        $date_after1 = strtotime('+1 day', $date_before1);

        $date_before2 = strtotime(jdtogregorian($time_before_JD2));
        $date_after2 = strtotime('+1 day', $date_before2);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before1);
        $utnow1 = $this->recode1['ut_time'];

        $utdatenow2 = strftime('%d.%m.%Y', $date_after1);
        $utnow2 = $this->recode1['ut_time'];

        $utdatenow3 = strftime('%d.%m.%Y', $date_before2);
        $utnow3 = $this->recode2['ut_time'];

        $utdatenow4 = strftime('%d.%m.%Y', $date_after2);
        $utnow4 = $this->recode2['ut_time'];

        $options1 = [
            'utdatenow' => $utdatenow1,
            'utnow' => $utnow1,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options2 = [
            'utdatenow' => $utdatenow2,
            'utnow' => $utnow2,
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options3 = [
            'utdatenow' => $utdatenow3,
            'utnow' => $utnow3,
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];
        $options4 = [
            'utdatenow' => $utdatenow4,
            'utnow' => $utnow4,
            'longitude' => $this->recode2['birth_lng'],
            'latitude' => $this->recode2['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);
        $out3 = $this->execData($options3);
        $out4 = $this->execData($options4);

        $calOut1 = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro1);
        $calOut2 = $this->getProgressionThirdprogressed($out3, $out4, $time_change_pro2);

        $original_data1 = $this->getOriginalData($calOut1);
        $original_data2 = $this->getOriginalData($calOut2);

        $this->arrayRemove($original_data1);
        $this->arrayRemove($original_data2);
        $details1 = $this->getPlanetHouseDetail($original_data1, $original_data1['hc1']);
        $details2 = $this->getPlanetHouseDetail($original_data2, $original_data1['hc1']);
        $phase1 = $this->planetPkPlanet($original_data1, $original_data2);
        $phase2 = $this->planetPkPlanet($original_data2, $original_data1);
        foreach ($phase1['planets'] as $k1 => $d1)
        {
            $details1['planets'][$k1]['phase'] = $d1['phase'];
            if (empty($d1['phase'])) $details1['planets'][$k1]['phase'] = NULL;
        }
        foreach ($phase2['planets'] as $k2 => $d2)
        {
            $details2['planets'][$k2]['phase'] = $d2['phase'];
            if (empty($d2['phase'])) $details2['planets'][$k2]['phase'] = NULL;
        }

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $details1['phase'] = $phase1['phase'];
            $details2['phase'] = $phase2['phase'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details1['planets'] = (object)$details1['planets'];
            $details2['planets'] = (object)$details2['planets'];
        } else
        {
            $details1 = $this->getStructure($details1);
            $details2 = $this->getStructure($details2);
        }

        return [$details1, $details2];
    }

    /**
     * 获取时空中点盘数据
     * 原理：两个档案的时间与空间取中点所生成的星盘
     * @return array
     */
    protected function getDavisonData(): array
    {
        $timestamp = ($this->recode1['ut_timestamp'] + $this->recode2['ut_timestamp']) / 2;

        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);

        $longitude = ($this->recode1['birth_lng'] + $this->recode2['birth_lng']) / 2;
        $latitude = ($this->recode1['birth_lat'] + $this->recode2['birth_lat']) / 2;

        $options = ['utdatenow' => $utdatenow, 'utnow' => $utnow, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取时空三次限盘数据
     * 原理：两个档案取得时空中点后的三次限盘
     * @param float $coef
     * @return array
     */
    protected function getDavisonThirdprogressedData($coef = 27.321661): array
    {
        $timestamp = ($this->recode1['ut_timestamp'] + $this->recode2['ut_timestamp']) / 2;

        $longitude = ($this->recode1['birth_lng'] + $this->recode2['birth_lng']) / 2;
        $latitude = ($this->recode1['birth_lat'] + $this->recode2['birth_lat']) / 2;

        [$year, $month, $day, $hour, $minute] = explode(',', date('Y,m,d,H,i', $timestamp));
        $birth_JD = gregoriantojd($month, $day, $year) + ($hour + ($minute / 60)) / 24;
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $prog_time_to_add = $days_alive / $coef; // 即本命后第几天

        $time_before_JD = $birth_JD + floor($prog_time_to_add);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro = $prog_time_to_add - floor($prog_time_to_add);

        $date_before = strtotime(jdtogregorian($time_before_JD));
        $date_after = strtotime('+1 day', $date_before);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before);
        $utnow1 = strftime('%H:%M:%S', $timestamp);

        $utdatenow2 = strftime('%d.%m.%Y', $date_after);
        $utnow2 = strftime('%H:%M:%S', $timestamp);

        $options1 = ['utdatenow' => $utdatenow1, 'utnow' => $utnow1, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];
        $options2 = ['utdatenow' => $utdatenow2, 'utnow' => $utnow2, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $calOut = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro);

        $original_data = $this->getOriginalData($calOut);
        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        // 绘制星盘时，不需要结构参数
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];
            $details['planets'] = (object)$details['planets'];
            $details['time1'] = date('Y-m-d H:i:s', $date_before);
        } else
        {
            $details = $this->getStructure($details, true);
        }

        return $details;
    }

    /**
     * 获取马克思盘数据
     * 原理：两个档案以原始时间空间的3/4与 1/4的比例产生的星盘
     * A* VS B 表示A对B的
     * B* VS A 表示B对A的
     * @return array
     */
    protected function getMarksData(): array
    {
        $timestamp = 0.75 * $this->recode1['ut_timestamp'] + 0.25 * $this->recode2['ut_timestamp'];
        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);
        $longitude = 0.75 * $this->recode1['birth_lng'] + 0.25 * $this->recode2['birth_lng'];
        $latitude = 0.75 * $this->recode1['birth_lat'] + 0.25 * $this->recode2['birth_lat'];

        $options = [
            'utdatenow' => $utdatenow,
            'utnow' => $utnow,
            'longitude' => $longitude,
            'latitude' => $latitude,
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);
        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取马克思盘三次限数据
     * 原理：两个档案以原始时间空间的3/4与 1/4的比例产生的星盘的三次限盘
     * @param float $coef
     * @return array
     */
    protected function getMarksThirdprogressedData($coef = 27.321661): array
    {
        $timestamp = 0.75 * $this->recode1['ut_timestamp'] + 0.25 * $this->recode2['ut_timestamp'];
        $longitude = 0.75 * $this->recode1['birth_lng'] + 0.25 * $this->recode2['birth_lng'];
        $latitude = 0.75 * $this->recode1['birth_lat'] + 0.25 * $this->recode2['birth_lat'];

        [$year, $month, $day, $hour, $minute] = explode(',', date('Y,m,d,H,i', $timestamp));
        $birth_JD = gregoriantojd($month, $day, $year) + ($hour + ($minute / 60)) / 24;
        $start_JD = $this->advance['ut_jd'];

        $days_alive = $start_JD - $birth_JD; // 总天数
        $prog_time_to_add = $days_alive / $coef; // 即本命后第几天

        $time_before_JD = $birth_JD + floor($prog_time_to_add);

        //变化比率 //就是$prog_time_to_add的去掉整数的小数
        $time_change_pro = $prog_time_to_add - floor($prog_time_to_add);

        $date_before = strtotime(jdtogregorian($time_before_JD));
        $date_after = strtotime('+1 day', $date_before);

        $utdatenow1 = strftime('%d.%m.%Y', $date_before);
        $utnow1 = strftime('%H:%M:%S', $timestamp);

        $utdatenow2 = strftime('%d.%m.%Y', $date_after);
        $utnow2 = strftime('%H:%M:%S', $timestamp);

        $options1 = ['utdatenow' => $utdatenow1, 'utnow' => $utnow1, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];
        $options2 = ['utdatenow' => $utdatenow2, 'utnow' => $utnow2, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);

        $calOut = $this->getProgressionThirdprogressed($out1, $out2, $time_change_pro);

        $original_data = $this->getOriginalData($calOut);
        $this->arrayRemove($original_data);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1']);
        $phase = $this->planetPkPlanet($original_data, $original_data, true);
        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];

            $details['planets'] = (object)$details['planets'];// 指定输出为object  防止所有行星全开时 类型改变
        }

        return $details;
    }

    /**
     * 获取卜卦盘数据
     */
    protected function getDivinationData(): array
    {
        $options = [
            'utdatenow' => $this->advance['ut_date'],
            'utnow' => $this->advance['ut_time'],
            'longitude' => $this->advance['longitude'],
            'latitude' => $this->advance['latitude'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->advance['year']);
        /**
         * 计算带月亮进程的相位信息
         */
        $phase = $this->divination_phase($original_data, $is_kongwang);

        $phases = [];

        foreach ($phase as $k => $d)
        {
            $details['planets'][$k]['phase'] = empty($d) ? null : $d;
            if (!empty($d))
            {
                foreach ($d as $j => $ph)
                {
                    $id1_id2 = explode('-', $j);
                    $phases[] = [
                        'id1' => $id1_id2[0],
                        'id2' => $id1_id2[1],
                        'phase_deg' => (int)$ph['phase_e'],
                    ];
                }
            }
        }
        // 重新索引数组
        $details['phase'] = $phases;

        $syzygy = $this->getSyzygyData($this->advance);

        $details['arabics'][8]['deg'] = $syzygy;
        $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
        $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);

        $details = $this->getStructure($details);

        $details['characteristic'] = $this->receptOrMutualRecept($details['planets']);

        if ($this->options['version'] > 1)
        {
            // 光线围攻
            $lightSiege = $this->lightSiege($details['planets']);
            if (!empty($lightSiege))
            {
                $details['characteristic'][9] = $lightSiege;
            }

            $between = $this->getBetweenHousePlanet($details['planets'], $details['houses']);
            if (!empty($between['between_house']))
            {
                // 夹宫
                $details['characteristic'][10] = $between['between_house'];
            }
            if (!empty($between['between_planet']))
            {
                // 夹星
                $details['characteristic'][11] = $between['between_planet'];
            }

            $gb = $this->getBetweenPlanetGoodOrBad($details['planets']);
            if (!empty($gb['bad']))
            {
                // 夹制
                $details['characteristic'][12] = $gb['bad'];
            }
            if (!empty($gb['good']))
            {
                // 夹辅
                $details['characteristic'][13] = $gb['good'];
            }
        }

        $details['fortune'] = $this->getFortScore($details, $this->advance['year'], $original_data['day_chart']);

        $details = $this->getHouseInfo($this->advance['ut_date'], $this->advance['ut_time'], $this->advance['longitude'], $this->advance['latitude'], $details);

        $details['planets'][1]['is_kongwang'] = $is_kongwang;
        $localtime = strtotime($this->advance['year'] . '-' . $this->advance['month'] . '-' . $this->advance['day'] . ' ' . $this->advance['hour'] . ':' . $this->advance['minute'] . ':00');
        $details['main_hour_planet'] = $this->hour_main_planet($localtime, $this->advance['longitude'], $this->advance['latitude']);
        $details['time'] = $localtime;
        // 指定输出为object  防止类型改变
        $details['characteristic'] = (object)$details['characteristic'];
        // 指定输出为object  防止所有行星全开时 类型改变
        $details['planets'] = (object)$details['planets'];

        return $details;
    }

    /**
     * 获取福点盘数据
     * 以福点所落的星座为第一宫，依次排序12 个宫位，形成一个新的盘。整宫制
     * @return array
     */
    protected function getFortuneData(): array
    {
        // 强制使用整宫制
        $this->options['h_sys'] = 'w';

        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        $houseStart = floor($original_data['p1'][14] / 30) * 30;

        for ($i = 1; $i < 13; $i++)
        {
            $original_data['hc1'][$i] = $houseStart;
            $houseStart += 30;
            if ($houseStart == 360) $houseStart = 0;
        }

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->recode1['year'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 17, 20]);

        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];
            $details = $this->getStructure($details);
            $details['characteristic'] = $this->receptOrMutualRecept($details['planets']);

            if ($this->options['version'] > 1)
            {
                // 光线围攻
                $lightSiege = $this->lightSiege($details['planets']);
                if (!empty($lightSiege))
                {
                    $details['characteristic'][9] = $this->lightSiege($details['planets']);
                }

                $between = $this->getBetweenHousePlanet($details['planets'], $details['houses']);
                if (!empty($between['between_house']))
                {
                    // 夹宫
                    $details['characteristic'][10] = $between['between_house'];
                }
                if (!empty($between['between_planet']))
                {
                    // 夹星
                    $details['characteristic'][11] = $between['between_planet'];
                }

                $gb = $this->getBetweenPlanetGoodOrBad($details['planets']);
                if (!empty($gb['bad']))
                {
                    // 夹制
                    $details['characteristic'][12] = $gb['bad'];
                }
                if (!empty($gb['good']))
                {
                    // 夹辅
                    $details['characteristic'][13] = $gb['good'];
                }
            }

            $syzygy = $this->getSyzygyData($this->recode1);

            $details['arabics'][8]['deg'] = $syzygy;
            $details['arabics'][8]['in_sign_deg'] = $this->inSignDeg($syzygy);
            $details['arabics'][8]['in_sign_id'] = InWhichSign($syzygy);
            // 福点分数
            $details['fortune'] = $this->getFortScore($details, $this->recode1['year'], $original_data['day_chart']);

            $details = $this->getHouseInfo($this->recode1['ut_date'], $this->recode1['ut_time'], $this->recode1['birth_lng'], $this->recode1['birth_lat'], $details, 'fortune');
            // 指定输出为object  防止类型改变
            $details['characteristic'] = (object)$details['characteristic'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details['planets'] = (object)$details['planets'];
        }

        return $details;
    }

    /**
     * 获取十二/三分度盘数据
     * Dodekatemorion
     * 整宫制
     * A) 将星体落在该星座的度数*12，加星体所在的星座的零度位置
     *      如：♈️白羊座10˚8‘ * 12 = 121˚36‘ = 121˚36‘  即♌狮子座️1˚36‘
     * B) 将星体落在该星座的度数*12，加星体所在的星座的本来位置
     *      如：
     * @param int $type [0=>12分盘,1=>13分盘]
     * @return array
     */
    protected function getDodekatemorionData($type = 0): array
    {
        // 强制使用整宫制
        $this->options['h_sys'] = 'w';

        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $original_data = $original_dataTmp = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        foreach ($original_data['p1'] as $k => $p1)
        {
            $original_data['p1'][$k] = $this->dodekatemorionCacl($p1, $type);
        }
        // 计算原始数据的希腊点信息，用于计算原始数据的十二分度
        $detailsTmp = $this->getPlanetHouseDetail($original_dataTmp, $original_data['hc1'], $this->recode1['year']);
        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->recode1['year']);

        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

        // 需要获取画盘所需数据
        if ($this->isAstrolabe === true)
        {
            $details['phase'] = $phase['phase'];
            $details = $this->getStructure($details);
            $details['characteristic'] = $this->receptOrMutualRecept($details['planets']);

            if ($this->options['version'] > 1)
            {
                // 光线围攻
                $lightSiege = $this->lightSiege($details['planets']);
                if (!empty($lightSiege))
                {
                    $details['characteristic'][9] = $this->lightSiege($details['planets']);
                }

                $between = $this->getBetweenHousePlanet($details['planets'], $details['houses']);
                if (!empty($between['between_house']))
                {
                    // 夹宫
                    $details['characteristic'][10] = $between['between_house'];
                }
                if (!empty($between['between_planet']))
                {
                    // 夹星
                    $details['characteristic'][11] = $between['between_planet'];
                }

                $gb = $this->getBetweenPlanetGoodOrBad($details['planets']);
                if (!empty($gb['bad']))
                {
                    // 夹制
                    $details['characteristic'][12] = $gb['bad'];
                }
                if (!empty($gb['good']))
                {
                    // 夹辅
                    $details['characteristic'][13] = $gb['good'];
                }
            }
            $syzygy = $this->getSyzygyData($this->recode1);
            $detailsTmp['arabics'][8]['deg'] = $syzygy;
            // 12/13分盘计算 12/13分度为原始数据计算希腊点后进行12/13分度计算
            foreach ($detailsTmp['arabics'] as $k => $ara)
            {
                $deg = $this->dodekatemorionCacl($ara['deg'], $type);
                $details['arabics'][$k]['deg'] = $deg;
                $details['arabics'][$k]['in_sign_deg'] = $this->inSignDeg($deg);
                $details['arabics'][$k]['in_sign_id'] = InWhichSign($deg);
            }
            // 福点分数
            $details['fortune'] = $this->getFortScore($details, $this->recode1['year'], $original_data['day_chart']);
            $details = $this->getHouseInfo($this->recode1['ut_date'], $this->recode1['ut_time'], $this->recode1['birth_lng'], $this->recode1['birth_lat'], $details, 'dodekatemorion' . $type);
            // 指定输出为object  防止类型改变
            $details['characteristic'] = (object)$details['characteristic'];
            // 指定输出为object  防止所有行星全开时 类型改变
            $details['planets'] = (object)$details['planets'];
        }
        return $details;
    }

    /**
     * 获取黄道星释盘数据
     * 方法1： 推算到黄道释放方法各星体掌管的年
     *      不涉及宫位，行星掌管的年份：
     *      太阳 19 月亮 25 水星 20 金星 8 火星 15
     *      土星 摩羯 27 /水瓶 30 木星 12
     *      或者：白羊15 金牛8 双子20 巨蟹25 狮子19 处女20 天秤8 天蝎15 射手12 摩羯27 水瓶30 双鱼12
     *      举例：福点：以所落星座的守护星掌管年份，依次按照黄道秩序去找守护星年份，类似法达
     *      365.2025/360 一般主要用 360
     *      需要做：日月金木水火土  上升、下降、中天、天底 福点、精神点、必需点、爱神点、勇气点、胜利点、复仇点
     * 方法 2：推算到黄道释放方法各星体掌管的年/月/日/时时间
     *      黄道一周的年/月/日/时总的时间就有了
     *      反正就是固定的调用十二星座掌管的时间
     */
    protected function getZodrelData(): array
    {
        $timestamp1 = $this->dealTime($this->recode1);
        $timestamp2 = $this->dealTime($this->advance);
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $utdatenow = strftime('%d.%m.%Y', $timestamp1);
        $utnow = strftime('%H:%M:%S', $timestamp1);
        // 强制使用整宫制
        $this->options['h_sys'] = 'w';

        $longitude = $this->recode1['longitude'] ?? ($this->recode1['long_deg'] + $this->recode1['long_min'] / 60) * $this->recode1['ew'];
        $latitude = $this->recode1['latitude'] ?? ($this->recode1['lat_deg'] + $this->recode1['lat_min'] / 60) * $this->recode1['ns'];

        $options = ['utdatenow' => $utdatenow, 'utnow' => $utnow, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out = $this->execData($options);

        $original_data = $this->getOriginalData($out);

        $this->arrayRemove($original_data);

        $details = $this->getPlanetHouseDetail($original_data, $original_data['hc1'], $this->recode1['year']);

        $phase = $this->planetPkPlanet($original_data, $original_data, true);

        foreach ($phase['planets'] as $k => $d)
        {
            $details['planets'][$k]['phase'] = $d['phase'];
            if (empty($d['phase'])) $details['planets'][$k]['phase'] = null;
        }

//        $pushFortune = $this->options['push_fortune'];
//        $pushTag = (string)substr($pushFortune, 0, 1);
//        $pushId = (int)substr($pushFortune, 1);
//
//        if ($pushTag === 'a')
//        {
//            // 希腊点落座 精神点、
//            $pushFortuneSign = 1;
//        } else
//        {
//            // 行星落座 四轴、古典七星、福点
//            $pushFortuneSign = $details['planets'][$pushId]['in_sign_id'] - 1;
//        }
        //
        /**
         * 白羊15 金牛8 双子20 巨蟹25 狮子19 处女20 天秤8 天蝎15 射手12 摩羯27 水瓶30 双鱼12
         * 摩羯座有两种配置 27/30  此处使用27
         */
        $signsYear = [15, 8, 20, 25, 19, 20, 8, 15, 12, 27, 30, 12];

        $birthJD = gregoriantojd(date('m', $timestamp1), date('d', $timestamp1), date('Y', $timestamp1)) + ((date('H', $timestamp1) + (date('i', $timestamp1) / 60)) / 24);
        $startJD = gregoriantojd(date('m', $timestamp2), date('d', $timestamp2), date('Y', $timestamp2)) + ((date('H', $timestamp2) + (date('i', $timestamp2) / 60)) / 24);
        $daysAlive = $startJD - $birthJD; // 总天数
        /**
         * 年系数有两种
         * 埃及 360
         * 非埃及 365.25
         */
        $yearsAgo = $daysAlive / 360;// 过去年份（埃及）
        // 计算12星座总共掌管年份
        $sumYear = array_sum($signsYear);
        $circleYear = $yearsAgo % $sumYear;
        $start = 0;

        foreach ($signsYear as $k => $year)
        {

            if ($circleYear <= $start += $year)
            {
                // 当前经历的星座id
//                $inSign = $k++;
                break;
            }
        }
        return $details;
    }

    /**
     * 卜卦相位 （月亮：月亮进程）
     * @param array $data 当前盘所有数据
     * @param bool $is_kongwang 月亮是否空亡
     * @return array
     */
    protected function divination_phase($data, &$is_kongwang): array
    {
        $phase = [];
        $phase_proess = [[], [], []];
        // 相位计算
        for ($i = 0; $i <= 20; $i++)
        {
            if (!isset($data['p1'][$i])) continue;
            // 初始化
            $phase[$i] = null;

            for ($j = 0; $j <= 20; $j++)
            {
                if (!isset($data['p1'][$j]) || $i === $j || ($i >= 17 && $j >= 17)) continue;
                $p1 = $data['p1'][$i];
                $p2 = $data['p1'][$j];

                $da = abs($p1 - $p2);
                if ($da > 180) $da = 360 - $da;
                $p1_orb = $this->options['planets_orb'][$i] ?? 0;// 星体1容许度
                $p2_orb = $this->options['planets_orb'][$j] ?? 0;// 星体2容许度
                $p_orb = $p1_orb + $p2_orb;
                // 相位判断
                $q = -1;

                $orb = 0;
                foreach ($this->options['asps_display'] as $asp)
                {
                    $asp_orb = $this->options['asps_orb'][$asp] ?? 0;

                    if (($da <= ($asp + $asp_orb + $p_orb)) && ($da >= ($asp - $asp_orb - $p_orb)))
                    {
                        $q = $asp;
                        $orb = $asp_orb + $p_orb;
                    }
                }
                // 计算出入相位
                if ($i >= ASC || $j >= ASC)
                {
                    $in_or_out = -1;
                } else
                {
                    $phase_orb = $this->degFormat(abs($da - $q), 6);
                    $in_or_out_status = $this->phaseInOrOut($q, $p1, $p2, $data['speed'][$i], $data['speed'][$j], $phase_orb);
                    if ($in_or_out_status) $in_or_out = 1;// 入相
                    else $in_or_out = 0;// 出相
                }

                $isPhase = $q > -1;

                // 计算月亮进程
                if ($i === 1 && $j < ASC)
                {
                    $in_sign_id1 = ceil($p1 / 30);
                    $in_sign_id2 = ceil($p2 / 30);
                    $pre_sign = $in_sign_id1 - 1 < 1 ? 12 : $in_sign_id1 - 1;
                    $next_sign = $in_sign_id1 + 1 > 12 ? 1 : $in_sign_id1 + 1;
                    $pre_cross_sign = $pre_sign > 6 ? $pre_sign - 6 : $pre_sign + 6;
                    $next_cross_sign = $next_sign > 6 ? $next_sign - 6 : $next_sign + 6;
                    $except_sign = [$pre_sign, $next_sign, $pre_cross_sign, $next_cross_sign];

                    if (in_array($in_sign_id2, $except_sign)) continue;// 先排除无法成相的四个星座 相邻两个星座

                    $in_sign_deg1 = $p1 - ($in_sign_id1 - 1) * 30;
                    $in_sign_deg2 = $p2 - ($in_sign_id2 - 1) * 30;

                    if ($isPhase)
                    {
                        $temp = [
                            'id' => $j,
                            'phase_e' => $q,
                            'phase_or_orb' => $this->degFormat($orb, 1),
                            'phase_orb' => $this->degFormat(abs($da - $q), 6),
                            'phase_change' => $in_or_out,
                            'phase_proess' => '过去'
                        ];
                        if ($in_sign_deg1 > $in_sign_deg2)
                        {
                            $phase_proess[0][$i . '-' . $j] = $temp;
                        } else
                        {
                            $temp['phase_proess'] = '进行';

                            $phase_proess[1][$i . '-' . $j] = $temp;
                        }
                    } elseif (!$isPhase)
                    {
                        $phaseTmp = $this->mod360(abs($in_sign_id1 - $in_sign_id2) * 30);
                        if ($phaseTmp > 180) $phaseTmp = 360 - $phaseTmp;

                        $temp = [
                            'id' => $j,
                            'phase_e' => $phaseTmp,
                            'phase_or_orb' => $this->degFormat($orb, 1),
                            'phase_orb' => $this->degFormat(abs($in_sign_deg1 - $in_sign_deg2), 6),
                            'phase_change' => $in_or_out,
                            'phase_proess' => '过去'
                        ];
                        if ($in_sign_deg1 > $in_sign_deg2)
                        {
                            $phase_proess[0][$i . '-' . $j] = $temp;
                        } else
                        {
                            $temp['phase_proess'] = '未来';

                            $phase_proess[2][$i . '-' . $j] = $temp;
                        }
                    }

                    $phase[1] = [];
                } // 非月亮相位正常显示
                elseif ($i !== 1 && $isPhase)
                {
                    $phase[$i][$i . '-' . $j] = [
                        'id' => $j,
                        'phase_e' => $q,
                        'phase_or_orb' => $this->degFormat($orb, 1),
                        'phase_orb' => $this->degFormat(abs($da - $q), 6),
                        'phase_change' => $in_or_out,
                    ];
                }
            }
        }
        /**
         * 对月亮所有进程进行排序
         */
        $phase_proess[0] = resort($phase_proess[0], 'phase_orb', 'DESC');
        $phase_proess[1] = resort($phase_proess[1], 'phase_orb', 'ASC');
        $phase_proess[2] = resort($phase_proess[2], 'phase_orb', 'ASC');
        /**
         * 没有进行相&&未来相 空亡！
         */
        if (empty($phase_proess[1]) && empty($phase_proess[2]))
        {
            $is_kongwang = true;
        } else
        {
            $is_kongwang = false;
        }
        /**
         * 月亮进程更新到月亮相位中
         */
        $phase[1] = array_merge($phase_proess[0], $phase_proess[1], $phase_proess[2]);
        if (!empty($phase[1]))
        {
            $phase[1] = array_values($phase[1]);
            $tp = [];
            foreach ($phase[1] as $ph1)
            {
                $tp[1 . '-' . $ph1['id']] = $ph1;
            }
            $phase[1] = $tp;
        }

        return $phase;
    }

    /**
     * 计算某时某地的时主星
     * @param null $timestamp 未处理过的当地时间
     * @param null $longitude 经度
     * @param null $latitude 纬度
     * @return mixed
     */
    protected function hour_main_planet($timestamp = null, $longitude = null, $latitude = null)
    {
        $planet_sequence = [0, 3, 2, 1, 6, 5, 4];// 周日日出后开始算
        $used = [];
        $j = 0;
        for ($i = 1; $i <= 7 * 24; $i++)
        {
            if ($j === 7) $j = 0;
            $used[] = $planet_sequence[$j];
            $j++;
        }
        //  周日为0  周一为1 ... 周六为6
        $start_week = (int)date('w', $timestamp);

        $start = $start_week * 24;

        $sun_info_now = $this->dateSunInfo($timestamp, $latitude * 1, $longitude * 1);
        /**
         * 日落之前
         */
        if ($timestamp <= $sun_info_now['sunset'])
        {
            $n = 0;
            $diff = (($sun_info_now['sunset'] - $sun_info_now['sunrise']) / 12);
            for ($s = $sun_info_now['sunrise']; $s <= $sun_info_now['sunset'];)
            {
                $next = $s + $diff;
                if ($timestamp >= $s && $timestamp <= $next)
                {
                    break;
                }
                $n++;
                $s = $next;
            }

            return $used[$start + $n];
        }

        $timestampTomorrow = $timestamp + 24 * 3600;

        // 求出下一天的日出时间
        $sun_info_tomorrow = $this->dateSunInfo($timestampTomorrow, $latitude, $longitude);
        $n = 0;
        $diff = (($sun_info_tomorrow['sunrise'] - $sun_info_now['sunset']) / 12);
        for ($s = $sun_info_now['sunset']; $s <= $sun_info_tomorrow['sunrise'];)
        {
            $next = $s + $diff;
            if ($timestamp >= $s && $timestamp <= $next)
            {
                break;
            }
            $n++;
            $s = $next;
        }

        return $used[$start + $n];
    }

    /**
     * 获取某时某地 太阳东升西落信息
     * @param null $time
     * @param float $latitude 规定纬度。
     * @param float $longitude 规定经度
     * 如果成功则返回一个数组，如果失败则返回 FALSE。
     * @return array
     */
    protected function dateSunInfo($time = null, $latitude = 31.7667, $longitude = 35.2333): array
    {
        $sun_info = date_sun_info($time, $latitude, $longitude);
        // TODO 解决 失败则返回 FALSE 后续处理
        return ['sunrise' => $sun_info['sunrise'], 'sunset' => $sun_info['sunset'], 'transit' => $sun_info['transit']];
    }

    /**
     * 保证度数在[0~360)之间
     * @param int $value
     * @return float
     */
    protected function mod360($value = 0): float
    {
        if ($value < 0)
        {
            $value += 360;
        } else if ($value >= 360)
        {
            $value -= 360;
        }
        return $value;
    }

    /**
     * 光线围攻
     * 只计算古典七星 日月水金火木土
     * 行星A与BC分别形成主相位（0，60，90，120，180）,则A被BC围攻
     * 行星容许：太阳17 月亮15 水星7 金星7 火星8 木星9 土星9
     * @param array $planets
     * @param bool $isAstrolabel 是否为前端展示使用
     * @return array
     */
    protected function lightSiege($planets = [], $isAstrolabel = true): array
    {
        $result = [];
        try
        {
            if ($isAstrolabel === false)
            {
                // 行星成相初始化
                $phases = [[], [], [], [], [], [], []];
                // 星体容许度 （半径容许）
                $orbs = [8.5, 7.5, 3.5, 3.5, 4, 4.5, 4.5];
                /**
                 * 仅单盘
                 */
                for ($i = 0; $i < 7; $i++)
                {
                    if (!isset($planets[$i])) continue;
                    for ($j = 0; $j < 7; $j++)
                    {
                        if (!isset($planets[$j]) || $i === $j) continue;
                        // 计算度数差值
                        $diff = abs($planets[$i]['deg'] - $planets[$j]['deg']);
                        // 度数差在180以内
                        $diff = $diff > 180 ? 360 - $diff : $diff;
                        // 当前最大容许度
                        $orOrb = $orbs[$i] + $orbs[$j];

                        $q = $phase_orb = -1;
                        // 合相
                        if ($diff <= $orOrb)
                        {
                            $q = 0;
                            $phase_orb = $diff;
                        } elseif ($diff >= (60 - $orOrb) && $diff <= (60 + $orOrb))
                        {
                            $q = 60;
                            $phase_orb = abs(60 - $diff);
                        } elseif ($diff >= (90 - $orOrb) && $diff <= (90 + $orOrb))
                        {
                            $q = 90;
                            $phase_orb = abs(90 - $diff);
                        } elseif ($diff >= (120 - $orOrb) && $diff <= (120 + $orOrb))
                        {
                            $q = 120;
                            $phase_orb = abs(120 - $diff);
                        } elseif ($diff >= (180 - $orOrb) && $diff <= (180 + $orOrb))
                        {
                            $q = 180;
                            $phase_orb = abs(180 - $diff);
                        }
                        if ($q > -1)
                        {
                            $phases[$i][] = [
                                'id1' => $i,
                                'id2' => $j,
                                'deg1' => $planets[$i]['deg'],
                                'deg2' => $planets[$j]['deg'],
                                'phase_deg' => $q,// $q
                                'phase_orb' => $phase_orb,
                                'phase_or_orb' => $orOrb
                            ];
                        }
                    }
                    $phaseICount = is_countable($phases[$i]) ? count($phases[$i]) : 0;
                    // 行星i至少与两颗星体成主相位
                    if ($phaseICount >= 2)
                    {
                        $min = 100;
                        for ($k = 0; $k < $phaseICount - 1; $k++)
                        {
                            for ($l = $k + 1; $l < $phaseICount; $l++)
                            {
                                $phaseOrbSum = $phases[$i][$k]['phase_orb'] + $phases[$i][$l]['phase_orb'];
                                if ($k < $l && $phaseOrbSum <= $min)
                                {
                                    $min = $phaseOrbSum;
                                    /**
                                     * 记录围攻
                                     * 单星体被多组星体围攻，取最紧密围攻
                                     * 最紧密：挨着当前星体最近的星体组
                                     */
                                    $result[$i] = [
                                        'planet_id' => $i,
                                        'id1' => $phases[$i][$k]['id2'],
                                        'id2' => $phases[$i][$l]['id2'],
                                        'deg1' => $phases[$i][$k]['phase_deg'],
                                        'deg2' => $phases[$i][$l]['phase_deg'],
                                    ];
                                }
                            }
                        }
                    }
                }
            } else
            {
                foreach ($planets as $pid => $planet)
                {
                    if (!empty($planet) && isset($planet['id']) && $planet['id'] <= 6 && !empty($planet['phase']) && is_countable($planet['phase']))
                    {
                        if (count($planet['phase']) >= 2)
                        {
                            $phases = [];
                            foreach ($planet['phase'] as $phase)
                            {
                                if ($phase['id'] < 7 && in_array($phase['phase_e'], [0, 60, 90, 120, 180]))
                                {
                                    $phases[] = $phase['id'];
                                }
                            }
                            // 与两颗星体成主相位
                            if (is_countable($phases) && count($phases) > 1)
                            {
                                $min = 100;
                                foreach ($phases as $c1)
                                {
                                    foreach ($phases as $c2)
                                    {
                                        // 容许度和
                                        $phaseOrbSum = $planet['phase'][$pid . '-' . $c1]['phase_orb'] + $planet['phase'][$pid . '-' . $c2]['phase_orb'];
                                        if ($c1 < $c2 && $phaseOrbSum < $min)
                                        {
                                            $min = $phaseOrbSum;
                                            $result[$pid] = [
                                                'planet_id' => $pid,
                                                'id1' => $c1,
                                                'id2' => $c2,
                                                'deg1' => $planet['phase'][$pid . '-' . $c1]['phase_e'],
                                                'deg2' => $planet['phase'][$pid . '-' . $c2]['phase_e'],
                                            ];
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception $e)
        {
            $this->error = 'lightSiege:' . $e->getMessage();
        }

        return array_merge($result);
    }

    /**
     * 光线传递
     * 若有3颗行星，其中运行速度最快的行星X，与A星汇合后离去，此时是离相位，向前追另一颗行星B，此时是入相位， 这种情况X 行星将 A 行星的光线传递至B行星。
     * @param array $planets
     */
    protected function lightTransmission($planets = [])
    {
//        try
//        {
//            if (!empty($planets))
//            {
//                echo 111;
//            }
//        }
//        catch (\Exception $e)
//        {
//
//        }
//        return false;
    }

    /**
     * 光线集中
     * 若有3颗行星，在黄道秩序运行最慢的行星A，能与其他两颗未呈现主相位的B行星和C行星入相位聚拢，并且运行较慢的行星被与之入相位的B行星和C行星有接纳互容关系。
     */
    protected function ConcentratedLight()
    {

    }

    /**
     * 挫败
     * 当2颗星即将形成完美相位时，在黄道秩序运行较慢的行星先于其它较慢的行星形成相位，而使原先黄道秩序运行较快的行星欲形成的相位落空。
     */
    protected function defeat()
    {

    }

    /**
     * 禁止
     * 当AB 这个 2 个行星即将形成相位时，有第三颗行星 C 介入，妨碍了原本期待的相位。
     */
    protected function forbid()
    {

    }

    /**
     * 折返
     * 当A行星靠近 B 行星，即将形成精准相位，但是没有完成的时候，A 或 B 行星发生了逆行，这就叫折返。
     */
    protected function retrace()
    {

    }

    /**
     * 夹制：A 星的出入相位都在火土凶星之间
     * 夹辅：A 星的出入相位都在日月金木吉星之间
     * @param array $planets 星体数据
     * @return array
     */
    protected function getBetweenPlanetGoodOrBad($planets = []): array
    {
        $result = [
            'good' => [],
            'bad' => [],
        ];
        try
        {
            foreach ($planets as $pid => $planet)
            {
                if (!empty($planet) && isset($planet['id']) && $planet['id'] <= 6)
                {
                    if (!empty($planet['phase']))
                    {
                        $inOut = ['good' => [[], []], 'bad' => [[], []]];
                        foreach ($planet['phase'] as $phase)
                        {
                            // 只看古典七星之间的相位
                            if ($phase['id'] < 7)
                            {
                                // 成相星体为火土凶星
                                if (in_array($phase['id'], [4, 6]))
                                {
                                    $inOut['bad'][$phase['phase_change']][] = $phase['id'];
                                }
                                if (in_array($phase['id'], [0, 1, 3, 5]))
                                {
                                    $inOut['good'][$phase['phase_change']][] = $phase['id'];
                                }
                            }
                        }
                        // 出入相位都在吉星之间
                        if (count($inOut['good'][0]) >= 0 && count($inOut['good'][1]) > 0)
                        {
                            foreach ($inOut['good'][0] as $g1)
                            {
                                foreach ($inOut['good'][1] as $g2)
                                {
                                    $result['good'][] = [
                                        'id1' => $g1,
                                        'id2' => $g2,
                                        'planet_id' => $pid
                                    ];
                                }
                            }
                        }
                        // 出入相位都在凶星之间
                        if (count($inOut['bad'][0]) >= 0 && count($inOut['bad'][1]) > 0)
                        {
                            foreach ($inOut['bad'][0] as $b1)
                            {
                                foreach ($inOut['bad'][1] as $b2)
                                {
                                    $result['bad'][] = [
                                        'id1' => $b1,
                                        'id2' => $b2,
                                        'planet_id' => $pid,
                                    ];
                                }
                            }
                        }
                    }
                }
            }

        }
        catch (Exception $e)
        {
            $this->error = 'getBetweenPlanetGoodOrBad:' . $e->getMessage();
        }
        return $result;
    }

    /**
     * 判断夹宫夹星
     * 夹宫：夹宫原则不超过 90 度，比如木星双鱼9 宫、金星金牛11 宫、太阳白羊10，10 宫就被金木夹，主要观察日月夹、金木夹、火土夹
     *      被夹的宫中没有星体，夹宫的星体在宫位两侧且夹宫星体中间没有其他星体干扰
     * 夹星：夹星原则不超过 90 度，主要观察日月夹、金木夹、火土夹
     * @param array $planets 星体数据数组
     * @param array $houses 宫位数据数组
     * @return array 返回夹宫夹星数据
     */
    protected function getBetweenHousePlanet($planets = [], $houses = []): array
    {
        $result = [
            'between_house' => [],
            'between_planet' => [],
        ];
        try
        {
            $pidsByDegAsc = [];
            for ($i = 0; $i < 7; $i++)
            {
                $pidsByDegAsc[] = [
                    'id' => $i,
                    'deg' => (float)$planets[$i]['deg'],
                    'in_sign_id' => (int)$planets[$i]['in_sign_id'],
                    'in_house_id' => (int)$planets[$i]['in_house_id']
                ];
            }
            // 将古典七星按度数进行排序
            $pidsByDegAsc = resort($pidsByDegAsc, 'deg', 'ASC');
            // 将第一、二个添加到最后
            $pidsByDegAsc[] = $pidsByDegAsc[0];
            $pidsByDegAsc[] = $pidsByDegAsc[1];

            foreach ($pidsByDegAsc as $k => $p)
            {
                // 由于前面将第一个添加到最后，所以到最后一个的时候跳过
                if ($k >= count($pidsByDegAsc) - 2)
                {
                    break;
                }
                // 两颗星体落宫位的差
                $inHouseIdDiff = abs($pidsByDegAsc[$k]['in_house_id'] - $pidsByDegAsc[$k + 1]['in_house_id']);
                /**
                 * 满足夹宫条件：夹宫的星体在宫位两侧
                 * [11-1]=12   [12-2]=11  [3-1]=2   [6-4]=5
                 */
                $isDiff2 = $inHouseIdDiff === 2;
                $isDiff10 = $inHouseIdDiff === 10;
                if ($isDiff2 || $isDiff10)
                {
                    if ($isDiff2)
                    {
                        // 获取被夹宫位ID 11-1=12   12-2=1
                        if ($pidsByDegAsc[$k]['in_house_id'] > $pidsByDegAsc[$k + 1]['in_house_id'])
                        {
                            $midHouse = $pidsByDegAsc[$k + 1]['in_house_id'] + 1;
                        } else
                        {
                            $midHouse = $pidsByDegAsc[$k]['in_house_id'] + 1;
                        }
                    } else
                    {
                        // 获取被夹宫位ID 11-1=12   12-2=1
                        if ($pidsByDegAsc[$k]['in_house_id'] <= $pidsByDegAsc[$k + 1]['in_house_id'])
                        {
                            $midHouse = $pidsByDegAsc[$k + 1]['in_house_id'] + 1;
                        } else
                        {
                            $midHouse = $pidsByDegAsc[$k]['in_house_id'] + 1;
                        }
                    }
                    $midHouse = $midHouse > 12 ? 1 : $midHouse;

                    /**
                     * 夹宫条件：被夹的宫中没有星体
                     */
                    $housePlanetNum = 0;
                    foreach ($houses[$midHouse]['in_house_area_planet_info'] as $hp)
                    {
                        if ($hp['id'] < 7)
                        {
                            $housePlanetNum = 1;
                            break;
                        }
                    }
                    // 形成夹宫
                    if ($housePlanetNum === 0)
                    {
                        $result['between_house'][] = [
                            'id1' => $pidsByDegAsc[$k]['id'],
                            'id2' => $pidsByDegAsc[$k + 1]['id'],
                            'house_id' => $midHouse
                        ];
                    }
                }

                /**
                 * 开始计算夹星
                 * 日月|金木|火土   夹或者被夹
                 */
                $planetDegDiff = abs($pidsByDegAsc[$k]['deg'] - $pidsByDegAsc[$k + 2]['deg']);
                // 夹星度数在90˚内
                if ($planetDegDiff < 90 || $planetDegDiff > 270)
                {
                    if (in_array($pidsByDegAsc[$k + 1]['id'], [0, 1, 3, 4, 5, 6], true)
                        || (in_array($pidsByDegAsc[$k]['id'], [0, 1], true) && in_array($pidsByDegAsc[$k + 2]['id'], [0, 1], true))
                        || (in_array($pidsByDegAsc[$k]['id'], [3, 5], true) && in_array($pidsByDegAsc[$k + 2]['id'], [3, 5], true))
                        || (in_array($pidsByDegAsc[$k]['id'], [4, 6], true) && in_array($pidsByDegAsc[$k + 2]['id'], [4, 6], true))
                    )
                    {
                        $result['between_planet'][] = [
                            'id1' => $pidsByDegAsc[$k]['id'],
                            'id2' => $pidsByDegAsc[$k + 2]['id'],
                            'planet_id' => $pidsByDegAsc[$k + 1]['id']
                        ];
                    }
                }
            }
        }
        catch (Exception $e)
        {
            $this->error = 'getBetweenHousePlanet' . $e->getMessage();
            $result = [
                'between_house' => [],
                'between_planet' => [],
            ];
        }

        return $result;
    }

    /**
     * 12|13分度计算
     * @param null $lon 黄道经度
     * @param int $type [0=>12分度,1=>13分度]
     * @return float|int
     */
    protected function dodekatemorionCacl($lon = null, $type = 0)
    {
        $tmp = 0;
        if ($lon !== null)
        {
            // 落星座 0-11
            $inSign = floor($lon / 30);
            // 所落星座的起始度数
            $inSignStartDeg = 30 * $inSign;
            if ($type === 0)
            {
                // 计算12分度
                $tmp = $inSignStartDeg + ($lon - $inSignStartDeg) * 12;
            } else
            {
                // 计算13分度
                $tmp = $lon + ($lon - $inSignStartDeg) * 12;
            }

            // 是黄道经度在 [0,360)之间
            $tmp -= floor($tmp / 360) * 360;
        }
        return $tmp;
    }

    /**
     * 数据库获取朔望点
     * @param array $timeinfo
     * @return false|float
     */
    protected function getSyzygyData($timeinfo = [])
    {
        try
        {
            $time = $this->dealTime($timeinfo);
            $result = (new SyzygyTIme())->getSyzygyData(['time' => $time]);
        }
        catch (ApiException $e)
        {
            $result = 0.0;
        }
        return $result;
    }

    /**
     * 获取新月度数 若无返回false
     * @param null $timestamp
     * @param int $type (-1=>出生前|1=>出生后|0=>TODO 最近的点 暂时不支持)
     * @return array|bool
     */
    public function calcSyzygyData($timestamp = null, $type = -1)
    {
        if ($timestamp !== null)
        {
            $needPhaseDeg = $this->getNeedPhaseDeg($timestamp);

            // 要偏移的天数 向下取整
            $d = $this->mod360($needPhaseDeg['find_phase'] + $needPhaseDeg['moon']['deg'] - $needPhaseDeg['sun']['deg']) / ($needPhaseDeg['moon']['speed'] - $needPhaseDeg['sun']['speed']);

            if ($d >= 1)
            {
                $change = floor($d) * 24 * 3600 * $type;
            } elseif ($d >= 1 / 24)
            {
                $change = 3600 * $type;
            } elseif ($d >= 1 / 24 / 60)
            {
                $change = 60 * $type;
            } else
            {
                $change = 1 * $type;
            }

            while (true)
            {
                $timestamp += (int)$change;

                $tmpNeedPhaseDeg = $this->getNeedPhaseDeg($timestamp);

                if ($needPhaseDeg['find_phase'] !== $tmpNeedPhaseDeg['find_phase'])
                {
                    $timestamp -= $change;
                    if ($change < $type * 3600)
                    {
                        $change = -3600;
                    } elseif ($change < $type * 60)
                    {
                        $change = -60;
                    } elseif ($change < $type * 1)
                    {
                        $change = -1;
                    } else
                    {
                        // 与数据库字段保持一致
                        return [
                            'time' => date('Y-m-d H:i:s', $timestamp),
                            'phase' => $needPhaseDeg['find_phase'],
                            'deg' => $tmpNeedPhaseDeg['moon']['deg']
                        ];
                    }
                }
            }
        }

        return false;
    }

    /**
     * 获取推运方向最近的月相度数 0||180
     * @param null $timestamp
     * @param int $type
     * @return array
     */
    protected function getNeedPhaseDeg($timestamp = null, $type = -1): array
    {
        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);
        $execStr = $this->getConfigFromFile('prefix') . " -b{$utdatenow} -ut{$utnow} -p01 -eswe -fls -g,  -head -n1 -s1d";
        unset($out);
        exec($execStr, $out);

        $sun = explode(',', $out[0]);
        $moon = explode(',', $out[1]);

        $sunDeg = $sun[0] * 1;
        $moonDeg = $moon[0] * 1;
        $sunSpeed = $sun[1] * 1;
        $moonSpeed = $moon[1] * 1;

        // 获取太阳精准成相180˚的度数
        $phaseSun180 = $this->mod360($sunDeg + 180);
        // 需要查找的最近的成相相位
        $findPhase = $type ? 0 : 180;
        /**
         * 以下为算法样例
         * $sunDeg = 10;$moonDeg = 193;// 180
         * $sunDeg = 10;$moonDeg = 189;// 0
         * $sunDeg = 10;$moonDeg = 13;// 0
         * $sunDeg = 10;$moonDeg = 8;// 180
         * $sunDeg = 359;$moonDeg = 358;// 180
         * $sunDeg = 359;$moonDeg = 180;// 180
         * $sunDeg = 359;$moonDeg = 178;// 0
         * $sunDeg = 359;$moonDeg = 1;// 0
         */
        // 以太阳度数为地平线起点，若为地平线以上，则先冲，否则先合
        if ($sunDeg + 180 < 360)
        {
            if ($moonDeg >= $sunDeg && $moonDeg <= $phaseSun180)
            {
                $findPhase = $type ? 180 : 0;
            }
        }// 若往前推，先成冲相 满月🌕
        elseif ($sunDeg + 180 >= 360)
        {
            if ($sunDeg > $phaseSun180)
            {
                if ($moonDeg > $sunDeg || $moonDeg <= $phaseSun180)
                {
                    $findPhase = $type ? 180 : 0;
                }
            }
        }

        $result = [
            'sun' => ['deg' => $sunDeg, 'speed' => $sunSpeed],
            'moon' => ['deg' => $moonDeg, 'speed' => $moonSpeed],
            'find_phase' => $findPhase
        ];

        return $result;
    }

    /**
     * 计算一段时间内所有的新满月时间点
     * 日月精准合相0˚||冲相180˚
     * @param int $start 起始时间 timestamp
     * @param int $years 需要计算多少年的数据
     * @param int $type 时间往前或往后推 -1往前 || 1往后
     * @return array
     * @throws \think\exception\DbException
     */
    public function calculateSyzygyData(int $start = null, int $years = 10, int $type = 1): array
    {
        $result = [];
        if ($start !== null)
        {
            $timestamp = $start;
            $ednTimestamp = strtotime("+$years year", $timestamp);

            $needPhaseDeg = $this->getNeedPhaseDeg($timestamp);

//            if ($type === -1)
//            {
//                // 要偏移的天数 向下取整
//                $d = (int)floor($this->mod360($needPhaseDeg['find_phase'] + $needPhaseDeg['moon']['deg'] - $needPhaseDeg['sun']['deg']) / ($needPhaseDeg['moon']['speed'] - $needPhaseDeg['sun']['speed']));
//
//            } else
//            {
////                $d = (int)floor($this->mod360($needPhaseDeg['find_phase'] + $needPhaseDeg['sun']['deg'] - $needPhaseDeg['moon']['deg']) / ($needPhaseDeg['moon']['speed'] - $needPhaseDeg['sun']['speed']));
//            }

            $findPhase = $needPhaseDeg['find_phase'];

            // 一小时
            $change = 1 * 24 * 3600 * $type;

            $n = 1;
            while (true)
            {
                // 时间进行推进
                $timestamp += $change;

                if ($timestamp >= $ednTimestamp)
                {
                    return $result;
                }
                $n++;

                $tmpNeedPhaseDeg = $this->getNeedPhaseDeg($timestamp);
                // 如果相位度数发生变化，则表示在当前阶段产生精准相位
                if ($findPhase !== $tmpNeedPhaseDeg['find_phase'])
                {
                    // 往回推一段到还未产生精准相位的地方，并将精度变小
                    $timestamp -= $change;
                    // 逆推
                    if ($type === -1)
                    {
                        // 若上一阶段为天，则将精度缩小为小时
                        if ($change < $type * 3600)
                        {
                            $change = $type * 3600;
                        }// 若上一阶段为小时，则将精度缩小为分钟
                        elseif ($change < $type * 60)
                        {
                            $change = $type * 60;
                        }// 若上一阶段为分钟，则将精度缩小为秒
                        elseif ($change < $type * 1)
                        {
                            $change = $type * 1;
                        }// 得到精准成相时间点 精确度为/s
                        else
                        {
                            $dbData = Db::table('wechat_backup_07_18_14_43_00.app_syzygy_time')->where('time', date('Y-m-d H:i:s', $timestamp))->find();
                            if (!$dbData)
                            {
                                $datetime = date('Y-m-d H:i:s', $timestamp);
                                Db::table('wechat_backup_07_18_14_43_00.app_syzygy_time')->insert([
                                    'time' => $datetime,
                                    'phase' => $findPhase,
                                    'deg' => $tmpNeedPhaseDeg['moon']['deg']
                                ]);
                                $result[] = [
                                    'deg' => $tmpNeedPhaseDeg['moon']['deg'],// 月亮度数
                                    'phase' => $findPhase,// 成相度数
                                    'timestamp' => $timestamp,// 精准成相时间 0时区
                                    'date' => date('Y-m-d H:i:s', $timestamp + 8 * 3600),// 精准成相时间 8时区
                                    'enddate' => date('Y-m-d H:i:s', $ednTimestamp + 8 * 3600),// 精准成相时间 8时区
                                    'num' => $n,
                                ];
                            }

                            $n = 1;

                            $findPhase = $findPhase === 0 ? 180 : 0;

                            // 要偏移的天数 向下取整
                            $d = (int)floor($this->mod360($findPhase + $tmpNeedPhaseDeg['moon']['deg'] - $tmpNeedPhaseDeg['sun']['deg']) / ($tmpNeedPhaseDeg['moon']['speed'] - $tmpNeedPhaseDeg['sun']['speed']));

                            $change = $d ? $d * 24 * 3600 * $type : 3600 * $type;
                        }
                    } else
                    {
                        // 若上一阶段为天，则将精度缩小为小时
                        if ($change > $type * 3600)
                        {
                            $change = $type * 3600;
                        }// 若上一阶段为小时，则将精度缩小为分钟
                        elseif ($change > $type * 60)
                        {
                            $change = $type * 60;
                        }// 若上一阶段为分钟，则将精度缩小为秒
                        elseif ($change > $type * 1)
                        {
                            $change = $type * 1;
                        }// 得到精准成相时间点 精确度为/s
                        else
                        {
                            $dbData = Db::table('wechat_backup_07_18_14_43_00.app_syzygy_time')->where('time', date('Y-m-d H:i:s', $timestamp))->find();
                            if (!$dbData)
                            {
                                $datetime = date('Y-m-d H:i:s', $timestamp);
                                Db::table('wechat_backup_07_18_14_43_00.app_syzygy_time')->insert([
                                    'time' => $datetime,
                                    'phase' => $findPhase,
                                    'deg' => $tmpNeedPhaseDeg['moon']['deg']
                                ]);
                                $result[] = [
                                    'deg' => $tmpNeedPhaseDeg['moon']['deg'],// 月亮度数
                                    'phase' => $findPhase,// 成相度数
                                    'timestamp' => $timestamp,// 精准成相时间 0时区
                                    'date' => date('Y-m-d H:i:s', $timestamp + 8 * 3600),// 精准成相时间 8时区
                                    'enddate' => date('Y-m-d H:i:s', $ednTimestamp + 8 * 3600),// 精准成相时间 8时区
                                    'num' => $n,
                                ];
                            }
//                            echo date('Y-m-d H:i:s', $timestamp + 8 * 3600) . ' ' . $findPhase . ' ' . $tmpNeedPhaseDeg['moon']['deg'] . ' <br/>';
                            $result[] = [
                                'deg' => $tmpNeedPhaseDeg['moon']['deg'],// 月亮度数
                                'phase' => $findPhase,// 成相度数
                                'timestamp' => $timestamp,// 精准成相时间 0时区
                                'date' => date('Y-m-d H:i:s', $timestamp + 8 * 3600),// 精准成相时间 8时区
                                'enddate' => date('Y-m-d H:i:s', $ednTimestamp + 8 * 3600),// 精准成相时间 8时区
                                'num' => $n
                            ];
                            $n = 1;

                            $findPhase = $findPhase === 0 ? 180 : 0;

//                            $d = (int)floor($this->mod360($findPhase + $tmpNeedPhaseDeg['sun']['deg'] - $tmpNeedPhaseDeg['moon']['deg']) / ($tmpNeedPhaseDeg['moon']['speed'] - $tmpNeedPhaseDeg['sun']['speed']));


                            $change = 1 * 24 * 3600 * $type;
                        }
                    }
                }
            }
        }

        return $result;
    }

    /**
     * 计算行星返照时间
     * @param int $p 行星ID 0=>太阳,1=>月亮
     * @param array $timeinfo1 出生时间地理位置信息
     * @param array $timeinfo2 推运时间地理位置信息
     * @return float|int
     */
    protected function calculatePlanetReturnTime($p = 0, $timeinfo1 = [], $timeinfo2 = [])
    {
        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = gregoriantojd($timeinfo1['ut_month'], $timeinfo1['ut_day'], $timeinfo1['ut_year']) + (($timeinfo1['ut_hour'] + ($timeinfo1['ut_minute'] / 60)) / 24) - 0.5;
        $start_JD = gregoriantojd($timeinfo2['ut_month'], $timeinfo2['ut_day'], $timeinfo2['ut_year']) + (($timeinfo2['ut_hour'] + ($timeinfo2['ut_minute'] / 60)) / 24) - 0.5;
        $days_alive = $start_JD - $birth_JD; // 总天数

        // 根据行星ID获取周期时间
        if ($p === 0)
        {
            $cycle = 365.2422;// 365.2422  365.2421990  365.25
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $now_before = strtotime("+$cycleAgo year", $this->recode1['ut_timestamp']);
        } elseif ($p === 1)
        {
            $cycle = 27.321661;
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $cycleAgo = floor($cycleAgo * $cycle);
            $now_before = strtotime("+$cycleAgo day", $this->recode1['ut_timestamp']);
        } else
        {
            $cycle = 365.2422;
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $now_before = strtotime("+$cycleAgo year", $this->recode1['ut_timestamp']);
        }
        $now_after = strtotime('+1 day', $now_before);

        // 那一天行星位置
        $longtitude1 = $this->getPlanetDegByTimestamp($p, $this->recode1['ut_timestamp']);
        // 前一天行星位置
        $longtitude2 = $this->getPlanetDegByTimestamp($p, $now_before);
        // 后一天行星位置
        $longtitude3 = $this->getPlanetDegByTimestamp($p, $now_after);

        if ($longtitude2 - $longtitude3 > 300)
        {
            $longtitude3 += 360;
        }

        if ($longtitude2 - $longtitude1 > 300)
        {
            $longtitude1 += 360;
        }

        // 度数差
        $diff_longtitude = abs($longtitude3 - $longtitude2);
        // 精确到秒
        $diff_minutes = 24 * 60 * 60;
        // 每秒钟走的度数
        $diff_influence = $diff_longtitude / $diff_minutes;
        // 需要多少时间  回到需要的度数 总秒钟数
        $second = floor(abs($longtitude1 - $longtitude2) / $diff_influence);

        if ($longtitude1 < $longtitude2) $now_before -= $second;

        else $now_before += $second;
        // 秒数
        $seconds = $now_before % 60;

        $timestamp = $now_before - $seconds - 600;
        // 一次获取60分钟每分钟行星的度数
        $degs = $this->getPlanetDegByTimestamp($p, $timestamp, 60, '1m');

        foreach ($degs as $i => $deg)
        {
            if ($longtitude1 > 360) $longtitude1 -= 360;
            //只支持顺行的行星
            if ($i > 0 && $degs[$i - 1] - $deg > 300) $deg += 360;
            $degDiff = ($deg * 1 - $longtitude1);
            if ($degDiff > 0 && $degDiff <= 1)
            {
                // 精确到分钟
                $t = (int)$timestamp + ($i - 1) * 60;
                $degsSecond = $this->getPlanetDegByTimestamp($p, $t, 60, '1s');
                foreach ($degsSecond as $j => $degSecond)
                {
                    if ($degSecond - $longtitude1 < 1 && $degSecond > $longtitude1)
                    {
                        // 精确到秒
                        return $t + $j;
                    }
                }
            }
        }
//        $n = 0;
//        for ($i = (int)$timestamp; $i <= $timestamp + 2400; $i += 60)
//        {
//            $deg = $this->getPlanetDegByTimestamp($p, $i);
//
//            $degDiff = ($longtitude1 - $deg);
//            $n++;
//            if ($degDiff < 0 && $degDiff > -1)
//            {
//                Log::write('返照盘推运次数：' . $n);
//                return $i - 60;
//                break;
//            }
//        }
        return $timestamp;
    }

    /**
     * 通过0时区时间戳 获取星体度数
     * @param int $p 需要获取度数的星体ID
     * @param int $timestamp 0时区的时间戳
     * @param int $n 需要的数据条数
     * @param string $s 每条数据间间隔的时长
     * @param string $l 需要获取的数据 l表示行星度数 s表示行星运行速度
     * @return float|array|null
     */
    public function getPlanetDegByTimestamp($p = 0, $timestamp = null, $n = 1, $s = '1m', $l = 'l')
    {
        $deg = null;
        if ($timestamp !== null)
        {
            $timestamp = (int)$timestamp;
            $utdatenow = strftime('%d.%m.%Y', $timestamp);
            $utnow = strftime('%H:%M:%S', $timestamp);
            $exec_str = $this->exec_prefix . " -b{$utdatenow} -ut{$utnow} -p{$p} -eswe -f{$l} -g, -head -n{$n} -s{$s} 2>&1";
            exec($exec_str, $out1);

            if (isset($out1[0]) && count($out1) === 1)
            {
                $deg = $out1[0] * 1;
            } else
            {
                return $out1;
            }
        }
        return $deg;
    }

    /**
     * 计算行星间的度数差
     * @param string $p1
     * @param string $p2
     * @param int $timestamp
     * @param int $n
     * @param string $s
     * @param string $l
     * @return mixed
     */
    public function getPlanetDegDistanceByTimestamp($p1 = '0', $p2 = '1', $timestamp = 0, $n = 1, $s = '1m', $l = 'l')
    {
        $timestamp = (int)$timestamp;
        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);
        $exec_str = $this->exec_prefix . " -b{$utdatenow} -ut{$utnow} -p{$p1} -d{$p2} -eswe -f{$l} -g, -head -n{$n} -s{$s} 2>&1";
        exec($exec_str, $out1);

        if (isset($out1[0]) && count($out1) === 1)
        {
            $out1 = $out1[0] * 1;
        }
        return $out1;
    }

    /**
     * 获取行星落宫数据 分宫制：p
     * @param int $timestamp
     * @param string $p
     * @param int $lon
     * @param int $lat
     * @param int $n
     * @param string $s
     * @param string $l
     * @return array
     */
    public function getPlanetHouseByTimestamp($timestamp = 0, $p = '0', $lon = 0, $lat = 0, $n = 1, $s = '1m', $l = 'l')
    {
        //   -b09.06.1983 -ut05:34:00 -p0123456789 -eswe -house116.08333333333,38.433333333333,p -fj -g, -head
        $timestamp = (int)$timestamp;
        $utdatenow = strftime('%d.%m.%Y', $timestamp);
        $utnow = strftime('%H:%M:%S', $timestamp);
        $exec_str = $this->exec_prefix . " -b{$utdatenow} -ut{$utnow} -p{$p} -eswe -house{$lon},{$lat},p -f{$l} -g, -head -n{$n} -s{$s} 2>&1";
        exec($exec_str, $out1);
        return array_values(array_filter($out1));
    }

    /**
     * 计算行星返照时间
     * @param int $p 行星ID 0=>太阳,1=>月亮
     * @param array $timeinfo1 出生时间地理位置信息
     * @param array $timeinfo2 推运时间地理位置信息
     * @return float|int
     */
    protected function calculatePlanetReturnTimeOld($p = 0, $timeinfo1 = [], $timeinfo2 = [])
    {
        $timestamp1 = $this->dealTime($timeinfo1);

        $longitude = $this->recode1['longitude'] ?? ($this->recode1['long_deg'] + $this->recode1['long_min'] / 60) * $this->recode1['ew'];
        $latitude = $this->recode1['latitude'] ?? ($this->recode1['lat_deg'] + $this->recode1['lat_min'] / 60) * $this->recode1['ns'];

        $timestamp2 = $this->dealTime($timeinfo2);

        // 检测时间
        $this->checkTime($this->recode1['ut_timestamp'], $this->advance['ut_timestamp']);

        $birth_JD = gregoriantojd(date('m', $timestamp1), date('d', $timestamp1), date('Y', $timestamp1)) + ((date('H', $timestamp1) + (date('i', $timestamp1) / 60)) / 24);
        $start_JD = gregoriantojd(date('m', $timestamp2), date('d', $timestamp2), date('Y', $timestamp2)) + ((date('H', $timestamp2) + (date('i', $timestamp2) / 60)) / 24);
        $days_alive = $start_JD - $birth_JD; // 总天数

        // 根据行星ID获取周期时间
        if ($p === 0)
        {
            $cycle = 365.2422;// 365.2422  365.2421990  365.25
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $now_before = strtotime("+$cycleAgo year", $timestamp1);
        } elseif ($p === 1)
        {
            $cycle = 27.321661;
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $dayAgo = floor($cycleAgo * $cycle);
            $now_before = strtotime("+$dayAgo day", $timestamp1);
        } else
        {
            $cycle = 365.2422;
            // 查询当前渡过多少个周期
            $cycleAgo = floor($days_alive / $cycle);
            $now_before = strtotime("+$cycleAgo year", $timestamp1);
        }
        $now_after = strtotime('+1 day', $now_before);

        $utdatenow = strftime('%d.%m.%Y', $timestamp1);
        $utnow = strftime('%H:%M:%S', $timestamp1);

        $utdatenow1 = strftime('%d.%m.%Y', $now_before);
        $utnow1 = strftime('%H:%M:%S', $now_before);

        $utdatenow2 = strftime('%d.%m.%Y', $now_after);
        $utnow2 = strftime('%H:%M:%S', $now_after);

        $options1 = ['utdatenow' => $utdatenow, 'utnow' => $utnow, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];
        $options2 = ['utdatenow' => $utdatenow1, 'utnow' => $utnow1, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];
        $options3 = ['utdatenow' => $utdatenow2, 'utnow' => $utnow2, 'longitude' => $longitude, 'latitude' => $latitude, 'h_sys' => $this->options['h_sys']];

        $out1 = $this->execData($options1);
        $out2 = $this->execData($options2);
        $out3 = $this->execData($options3);

        // 出生生日那一天行星位置
        $longtitude1 = $this->degFormat(explode(',', $out1[$p])[0] * 1, 3);
        // 当年生日前一天的行星位置
        $longtitude2 = $this->degFormat(explode(',', $out2[$p])[0] * 1, 3);
        // 当年生日后一天行星位置
        $longtitude3 = $this->degFormat(explode(',', $out3[$p])[0] * 1, 3);

        $diff_longtitude = $this->degFormat(abs($longtitude3 - $longtitude2), 6);//度数差

        $diff_minutes = 24 * 60 * 60;//精确到秒

        $diff_influence = $diff_longtitude / $diff_minutes;// 每秒钟走的度数

        // 需要多少时间  回到需要的度数
        $second = floor(abs($longtitude1 - $longtitude2) / $diff_influence);// 总秒钟数

        if ($longtitude1 < $longtitude2) $now_before -= $second;

        else $now_before += $second;

        $seconds = $now_before % 60;// 秒数

//        $timestamp = $seconds >= 30 ? $now_before + 60 - $seconds : $now_before - $seconds;// 只精确到分钟
//        $timestamp = $now_before;
        return $now_before - $seconds;

//        return $timestamp;
    }

    /**
     * 将准了地址信息 转换成经纬度 默认使用出生地
     * @param $longitude float 默认返回值，若未传值，则默认使用当前档案中的出生地信息
     * @param $latitude float 默认返回值，若未传值，则默认使用当前档案中的出生地信息
     * @return array
     */
    protected function LivePlaceToLngLat($longitude = null, $latitude = null): array
    {
        try
        {
            $locations = $this->getLocations();

            $lng_lat = $locations[$this->recode1['live_country'] . '-' . $this->recode1['live_province'] . '-' . $this->recode1['live_city']];
            $longitude = $lng_lat['longitude'];
            $latitude = $lng_lat['latitude'];
        }
        catch (Exception $e)
        {
            if ($longitude === null)
            {
                $longitude = $this->recode1['birth_lng'] ?? ($this->recode1['long_deg'] + $this->recode1['long_min'] / 60) * $this->recode1['ew'];
            }
            if ($latitude === null)
            {
                $latitude = $this->recode1['birth_lat'] ?? ($this->recode1['lat_deg'] + $this->recode1['lat_min'] / 60) * $this->recode1['ns'];
            }
        }
        return [$longitude, $latitude];
    }

    /**
     * 获取地址文件数据
     */
    public function getLocations()
    {
        $locationFile = 'location.json';
        $LocationDir = RUNTIME_PATH . 'location';
        $originFile = ROOT_PATH . 'XZNSLocationDataInfo.json';
        $result = [];
        try
        {
            $filePath = $LocationDir . DS . $locationFile;
            if (file_exists($filePath))
            {
                $result = json_decode(file_get_contents($filePath), true);
            } else
            {
                $originLocations = json_decode(file_get_contents($originFile), true);

                foreach ($originLocations as $country)
                {
                    foreach ($country['children'] as $province)
                    {
                        foreach ($province['children'] as $city)
                        {
                            $longitude = ($city['long_deg'] + $city['long_min'] / 60) * $city['ew'];
                            $latitude = ($city['lat_deg'] + $city['lat_min'] / 60) * $city['ns'];
                            $result[$country['text'] . '-' . $province['text'] . '-' . $city['text']] = [
                                'longitude' => $longitude,
                                'latitude' => $latitude,
                                'code_country' => $country['value'],
                                'code_province' => $province['value'],
                                'code_city' => $city['value'],
                            ];
                        }
                    }
                }
                Util::createFile($locationFile, json_encode($result, true), 'location');
            }
        }
        catch (Exception $e)
        {
            Log::write('getLocations:' . $e->getMessage(), 'error', true);
            $result = [];
        }
        return $result;
    }


    /**
     * 获取档案星盘数据
     * @return array
     */
    public function getTheRecodeAstro()
    {
        $options = [
            'utdatenow' => $this->recode1['ut_date'],
            'utnow' => $this->recode1['ut_time'],
            'longitude' => $this->recode1['birth_lng'],
            'latitude' => $this->recode1['birth_lat'],
            'h_sys' => $this->options['h_sys']
        ];

        $out = $this->execData($options);

        $data = $this->getOriginalData($out);

        $result = [];
        $result['sun'] = InWhichSign($data['p1'][0]) . '-' . InWhichHouse($data['p1'][0], $data['hc1']) . '-' . $data['p1'][0];
        $result['moon'] = InWhichSign($data['p1'][1]) . '-' . InWhichHouse($data['p1'][1], $data['hc1']) . '-' . $data['p1'][1];
        $result['merc'] = InWhichSign($data['p1'][2]) . '-' . InWhichHouse($data['p1'][2], $data['hc1']) . '-' . $data['p1'][2];
        $result['venu'] = InWhichSign($data['p1'][3]) . '-' . InWhichHouse($data['p1'][3], $data['hc1']) . '-' . $data['p1'][3];
        $result['mars'] = InWhichSign($data['p1'][4]) . '-' . InWhichHouse($data['p1'][4], $data['hc1']) . '-' . $data['p1'][4];
        $result['jupi'] = InWhichSign($data['p1'][5]) . '-' . InWhichHouse($data['p1'][5], $data['hc1']) . '-' . $data['p1'][5];
        $result['satu'] = InWhichSign($data['p1'][6]) . '-' . InWhichHouse($data['p1'][6], $data['hc1']) . '-' . $data['p1'][6];
        $result['non'] = InWhichSign($data['p1'][12]) . '-' . InWhichHouse($data['p1'][12], $data['hc1']) . '-' . $data['p1'][12];
        $result['lili'] = InWhichSign($data['p1'][11]) . '-' . InWhichHouse($data['p1'][11], $data['hc1']) . '-' . $data['p1'][11];
        $result['juno'] = InWhichSign($data['p1'][13]) . '-' . InWhichHouse($data['p1'][13], $data['hc1']) . '-' . $data['p1'][13];
        $result['asc'] = InWhichSign($data['p1'][17]) . '-' . InWhichHouse($data['p1'][17], $data['hc1']) . '-' . $data['p1'][17];
        $result['mc'] = InWhichSign($data['p1'][20]) . '-' . InWhichHouse($data['p1'][20], $data['hc1']) . '-' . $data['p1'][20];

        return $result;
    }

}
